bitkeeper revision 1.1236.1.149 (42492762NRUXAIqtzpmd2lX5HSPVog)
authortjd21@arcadians.cl.cam.ac.uk <tjd21@arcadians.cl.cam.ac.uk>
Tue, 29 Mar 2005 10:01:06 +0000 (10:01 +0000)
committertjd21@arcadians.cl.cam.ac.uk <tjd21@arcadians.cl.cam.ac.uk>
Tue, 29 Mar 2005 10:01:06 +0000 (10:01 +0000)
Added the mbootpack tool, which packages multiboot boot files and
disguises them as a linux bzImage.  Useful for booting Xen using
pxelinux, or another linux-only bootloader.

Signed-off-by: Tim Deegan <Tim.Deegan@cl.cam.ac.uk>
14 files changed:
.rootkeys
BitKeeper/etc/logging_ok
tools/misc/Makefile
tools/misc/mbootpack/GPL [new file with mode: 0644]
tools/misc/mbootpack/Makefile [new file with mode: 0644]
tools/misc/mbootpack/README [new file with mode: 0644]
tools/misc/mbootpack/bin2c.c [new file with mode: 0644]
tools/misc/mbootpack/bootsect.S [new file with mode: 0644]
tools/misc/mbootpack/buildimage.c [new file with mode: 0644]
tools/misc/mbootpack/mb_header.h [new file with mode: 0644]
tools/misc/mbootpack/mb_info.h [new file with mode: 0644]
tools/misc/mbootpack/mbootpack.c [new file with mode: 0644]
tools/misc/mbootpack/mbootpack.h [new file with mode: 0644]
tools/misc/mbootpack/setup.S [new file with mode: 0644]

index c93eea13ace27e7adc445849e83e92f1960b07a7..fac49380c58559ece84cd990fc564275d33989f1 100644 (file)
--- a/.rootkeys
+++ b/.rootkeys
 41a216ca7mgVSnCBHPCLkGOIqPS1CQ tools/libxutil/util.h
 3f776bd2Xd-dUcPKlPN2vG89VGtfvQ tools/misc/Makefile
 40ab2cfawIw8tsYo0dQKtp83h4qfTQ tools/misc/fakei386xen
+4249273cDOw6_uLUPvvUwWU1ZrJxnQ tools/misc/mbootpack/GPL
+4249273cSmj2h8Fj3UpTg0g-k6CLsA tools/misc/mbootpack/Makefile
+4249273c8gKIttF1QPiczvGo5AEOeA tools/misc/mbootpack/README
+4249273c4N4PAkvt3trNlto4h76k8A tools/misc/mbootpack/bin2c.c
+4249273cISg5nhW1Pt7OJ0jFu343ig tools/misc/mbootpack/bootsect.S
+4249273cUiz8CgLqnG7XYFa8x5-MoQ tools/misc/mbootpack/buildimage.c
+4249273c_gZ2yI_h-ci66E1Y5oSEPA tools/misc/mbootpack/mb_header.h
+4249273cWnlW0-lOIYua1bkKirn6vA tools/misc/mbootpack/mb_info.h
+4249273cA8LI3IMaSuhLOjykuMeQJA tools/misc/mbootpack/mbootpack.c
+4249273cVTgyv2HYd-mC29IDaz0-mg tools/misc/mbootpack/mbootpack.h
+4249273cLXQbRWFp_v-FqcyOm0sYtg tools/misc/mbootpack/setup.S
 3f6dc136ZKOjd8PIqLbFBl_v-rnkGg tools/misc/miniterm/Makefile
 3f6dc140C8tAeBfroAF24VrmCS4v_w tools/misc/miniterm/README
 3f6dc142IHaf6XIcAYGmhV9nNSIHFQ tools/misc/miniterm/miniterm.c
index a5cd08799de07bb147b27dd05356b8b7f7ba16e9..fb88f12f887c220b529f41021ca4881d267bf531 100644 (file)
@@ -81,6 +81,7 @@ smh22@uridium.cl.cam.ac.uk
 sos22@donkeykong.cl.cam.ac.uk
 sos22@douglas.cl.cam.ac.uk
 sos22@labyrinth.cl.cam.ac.uk
+tjd21@arcadians.cl.cam.ac.uk
 tlh20@elite.cl.cam.ac.uk
 tlh20@labyrinth.cl.cam.ac.uk
 tw275@labyrinth.cl.cam.ac.uk
index b815072184a8527bfd7bf714d53e90b065107f47..f12193eb6e230a32e277bf373272abc1af4453b9 100644 (file)
@@ -21,6 +21,7 @@ INSTALL_SBIN = netfix xm xend xensv xenperf
 all: build
 build: $(TARGETS)
        $(MAKE) -C miniterm
+       $(MAKE) -C mbootpack
 
 install: build
        [ -d $(DESTDIR)/usr/bin ] || $(INSTALL_DIR) $(DESTDIR)/usr/bin
@@ -29,10 +30,13 @@ install: build
        $(INSTALL_PROG) $(INSTALL_SBIN) $(DESTDIR)/usr/sbin
 #       No sense in installing miniterm on the Xen box.
 #      $(MAKE) -C miniterm install
+#       Likewise mbootpack
+#      $(MAKE) -C mbootpack install
 
 clean:
        $(RM) *.o $(TARGETS) *~
        $(MAKE) -C miniterm clean
+       $(MAKE) -C mbootpack clean
 
 %.o: %.c $(HDRS) Makefile
        $(CC) -c $(CFLAGS) -o $@ $<
diff --git a/tools/misc/mbootpack/GPL b/tools/misc/mbootpack/GPL
new file mode 100644 (file)
index 0000000..5b6e7c6
--- /dev/null
@@ -0,0 +1,340 @@
+                   GNU GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                       59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+\f
+                   GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+\f
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+\f
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+\f
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                           NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+           How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/tools/misc/mbootpack/Makefile b/tools/misc/mbootpack/Makefile
new file mode 100644 (file)
index 0000000..c0bb60e
--- /dev/null
@@ -0,0 +1,97 @@
+#
+#  Makefile for mbootpack
+#
+INSTALL                = install
+INSTALL_PROG   = $(INSTALL) -m0755
+INSTALL_DIR    = $(INSTALL) -d -m0755
+
+XEN_ROOT=../../..
+include $(XEN_ROOT)/tools/Rules.mk
+
+CFLAGS   += -Wall -Werror -O3 
+
+INCLUDES += -I $(XEN_XC)
+INCLUDES += -I $(XEN_LIBXC)
+CFLAGS   += $(INCLUDES)
+
+HDRS     = $(wildcard *.h)
+
+TARGETS  = mbootpack
+
+INSTALL_BIN  = mbootpack
+INSTALL_SBIN =
+
+all: build
+build: $(TARGETS)
+
+install: build
+       $(INSTALL_PROG) $(INSTALL_BIN) $(DESTDIR)/usr/bin
+
+#
+#  What object files need building for the program
+#
+
+OBJS   := mbootpack.o buildimage.o
+DEPS   := mbootpack.d buildimage.d
+
+# 
+#  Tools etc.
+#
+
+RM     := rm -f
+GDB    := gdb
+INCS   := -I. -I-
+DEFS   := 
+LDFLAGS        := 
+CC     := gcc
+CFLAGS         := -W -Wall -Wpointer-arith -Wcast-qual -Wno-unused -Wno-format
+CFLAGS += -Wmissing-prototypes
+#CFLAGS        += -pipe -g -O0 -Wcast-align
+CFLAGS += -pipe -O3 
+
+#
+#  Rules
+#
+
+mbootpack: $(OBJS)
+       $(CC) -o $@ $(filter-out %.a, $^) $(LDFLAGS)
+
+clean: FRC
+       $(RM) mbootpack *.o *.d bootsect setup bzimage_header.c bin2c
+
+bootsect: bootsect.S
+       $(CC) $(CFLAGS) $(INCS) $(DEFS) -D__MB_ASM -c bootsect.S -o bootsect.o
+       $(LD) -m elf_i386 -Ttext 0x0 -s --oformat binary bootsect.o -o $@
+
+setup: setup.S
+       $(CC) $(CFLAGS) $(INCS) $(DEFS) -D__MB_ASM -c setup.S -o setup.o
+       $(LD) -m elf_i386 -Ttext 0x0 -s --oformat binary setup.o -o $@
+
+bin2c: bin2c.o 
+       $(CC) -o $@ $^ 
+
+bzimage_header.c: bootsect setup bin2c
+       ./bin2c -n 8 -b1 -a bzimage_bootsect bootsect > bzimage_header.c
+       ./bin2c -n 8 -b1 -a bzimage_setup setup >> bzimage_header.c
+
+buildimage.c buildimage.d: bzimage_header.c
+
+%.o: %.S
+       $(CC) $(CFLAGS) $(INCS) $(DEFS) -c $< -o $@
+
+%.o: %.c
+       $(CC) $(CFLAGS) $(INCS) $(DEFS) -c $< -o $@
+
+%.d: %.c
+       $(CC) $(CFLAGS) $(INCS) $(DEFS) -M $< > $@
+
+FRC: 
+.PHONY:: all FRC clean gdb
+.PRECIOUS: $(OBJS) $(OBJS:.o=.c) $(DEPS)
+.SUFFIXES: 
+
+-include $(DEPS)
+
+#
+#  EOF
+#
diff --git a/tools/misc/mbootpack/README b/tools/misc/mbootpack/README
new file mode 100644 (file)
index 0000000..0751652
--- /dev/null
@@ -0,0 +1,77 @@
+
+mbootpack
+---------
+
+This is a utility to take a multiboot kernel and modules and repackage
+them in a form that a standard linux bootloader will be able to load them.
+It statically allocates memory addresses based on a 'standard' PC memory 
+layout, and then saves the image of the loaded system, along with an 
+almost-standard linux bzImage header which takes care of the start-of-day 
+requirements of a multiboot kernel (setting up 32-bit protected mode, etc.)
+
+Example invocation, to package a xen VMM and xenlinux guest and initrd:
+
+   mbootpack -o bzImage -m ./xenlinux -m ./initrd.img ./xen-image
+
+You can now boot the 'bzImage' file using your favourite linux bootloader.
+
+The kernel command line will be provided at boot time by the bootloader
+(you can specify a kernel command-line using the '-c' flag, but it will
+be overridden at boot time unledd the bootloder provides an entirely
+empty command line).  If you wan to override the command line for the
+first module (i.e. domain 0 kernel in Xen) at boot time, append ' -- '
+and the module commadn line to the bootloader command line, e.g.:
+
+  boot: bzImage com1=9600,8n1 console=com1 dom0_mem=49152 -- root=/dev/sda3 ro console=ttyS0,9600n8 
+
+Everything before the '--' is passed to the kernel (xen) as its command
+line; everything after is passed to the first module (xenlinux).
+
+This is ALPHA code: there are execution paths which have *not* been
+tested, though it works for loading the Xen hypervisor using GrUB, LILO
+or SYSLINUX.  Bug reports and patches are very welcome.
+
+Possible features for future versions (all look possible, if there's any 
+demand for them):
+
+    - support for kernels that load below 1MB
+    - zImage-style compressed images
+    - sane error messgaes for insane load addresses
+    - support for the MULTIBOOT_VIDEO_MODE bit
+    - proper support for passing E820h memory-maps from bzImage
+
+
+Tim Deegan <tjd21@cl.cam.ac.uk>, March 2005
+
+
+
+License and attributions
+------------------------
+
+The bzImage header block was originally taken from the Linux kernel.
+http://www.kernel.org/
+
+Some parts of the Multiboot loader code are based on GNU GRUB.
+mb_info.h and mb_header.h are taken from GNU GRUB.
+http://www.gnu.org/software/grub/
+
+Bin2C was written by Nicolas Doualot; I tidied it a bit for a clean compile.
+http://slubman.celeonet.fr/program.php?style=Default&project=bin2c
+
+All other code is copyright (C) 2003-2005  Tim Deegan (tjd21@cl.cam.ac.uk)
+
+mbootpack is distributed under the GNU General Public License: see "GPL"
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
diff --git a/tools/misc/mbootpack/bin2c.c b/tools/misc/mbootpack/bin2c.c
new file mode 100644 (file)
index 0000000..609335d
--- /dev/null
@@ -0,0 +1,356 @@
+/***************************************************************************************
+   Project informations:
+      Project:    bin2c
+      Version:    1.00
+      Plateforme: PC
+      Copyright:  DNDD.INC
+      Date:       28/03/2004
+
+   File informations:
+      Name:       bin2c.c
+      Description:Convert any file to a C array
+
+   Author informations:
+      Author:     DOUALOT Nicolas
+      E-Mail:     slubman@laposte.net
+      site:       http://membres.lycos.fr/slubman/gp32
+***************************************************************************************/
+
+
+#include <stdio.h>                             /*perror */
+#include <sys/mman.h>                  /*PROT_READ,MAP_xxx */
+#include <fcntl.h>                             /*O_RDONLY */
+#include <sys/stat.h>                  /*stat */
+#include <stdlib.h>                            /*atoi */
+#include <string.h>                            /*strcmp */
+#include <ctype.h>                             /*toupper */
+
+#define VERSION "1.10"
+
+
+static void help(void)
+{
+       fprintf(stdout, "\nbin2c v"VERSION"\n");
+       fprintf(stdout, "Slubman DevSoft (c)2003-2004 slubman.dndd@laposte.net \n\n");
+
+       fprintf(stdout, "Usage: bin2c [flags] <infile>\n\n");
+
+       //fprintf(stdout, "\t-quiet      :\tdon't output standard messages\n");
+       //fprintf(stdout, "\t-slash      :\tappend backslash at end of line\n");
+       fprintf(stdout, "\t-n <count>  :\tnumber of items per line\n");
+       fprintf(stdout, "\t-b1         :\tgenerate unsigned char array\n");
+       fprintf(stdout, "\t-b2         :\tgenerate unsigned short  array\n");
+       fprintf(stdout, "\t-b4         :\tgenerate unsigned long array\n");
+       fprintf(stdout, "\t-a <name>   :\tgenerate an array with given name\n");
+       fprintf(stdout, "\t-ss <nr>    :\tskip number of bytes at begin of inputfile\n");
+       fprintf(stdout, "\t-se <nr>    :\tskip number of bytes at end of inputfile\n");
+       fprintf(stdout, "\t-lb <nr>    :\tinsert an additionally linebreak every nr line\n");
+       fprintf(stdout, "\t-h          :\tproduce an header\n");
+       fprintf(stdout, "\tinfile      :\tname of infile\n");
+       fprintf(stdout, "\toutfile     :\tname of outfile (use \"-\" for stdout)\n\n");
+
+       fprintf(stdout, " \tconverts binary file to C array data\n");
+}
+
+static void UnknownFlag(char *flag)
+{
+       fprintf(stderr, "Error: unknown flag %s\n", flag);
+       help();
+       exit(EXIT_FAILURE);
+}
+
+static void WriteHeader(FILE * outFile, char *oFileName, char *iFileName)
+{
+       // File Header
+       fprintf(outFile, "/***************************************************************************************\n");
+       fprintf(outFile, "*   File Name:\n");
+       fprintf(outFile, "*      Name:       %s\n", oFileName);
+       fprintf(outFile, "*      From:       %s\n", iFileName);
+       fprintf(outFile, "*      Created by :bin2c v"VERSION"\n*\n");
+       fprintf(outFile, "*   bin2c v"VERSION":\n");
+       fprintf(outFile, "*      Author:     DOUALOT Nicolas\n");
+       fprintf(outFile, "*      E-Mail:     slubman.dndd@laposte.net\n");
+       fprintf(outFile, "*      site:       http://www.slubman.linux-fan.com/\n");
+       fprintf(outFile, "***************************************************************************************/\n\n");
+}
+
+int main(int argc, char *argv[])
+{
+       FILE *inFile = stdin, *outFile = stdout;
+       int a, i, nbLine = 0;
+       unsigned char *memory;
+       struct stat st;
+
+       // Options
+       char arrayName[255] = "array";  // Array name
+       char *iFileName = NULL;         // File to convert
+       char *oFileName = NULL;         // File to write
+       int bpd = 1;                            // Array item length
+       int lb = 0;                                     // Array blank line each lb line(s)
+       int nbCol = 15;                                 // Nuber of items per line
+       int SkeepStart = 0;                     // Number of byte to skip at file begining
+       int SkeepEnd = 0;                       // Number of byte to skip at file end
+       int header = 0;                         // Produce an header
+
+       // Is there the good number of arguments
+       if (argc < 2)
+       {
+               help();
+               return 0;
+       }
+
+       // On récupère les arguments (Ready for more options)
+       for (a = 1; a < argc; a++)
+       {
+               // An option
+               if (argv[a][0] == '-')
+               {
+                       // Wich flag is it ?
+                       switch (argv[a][1])
+                       {
+                                       // Writting on stdout
+                               case 0:
+                                       printf("%s\n", argv[a]);
+                                       outFile = stdout;
+                                       break;
+
+                                       // ArrayName flag
+                               case 'a':
+                                       strcpy(arrayName, argv[++a]);
+                                       break;
+
+                                       // Data type
+                               case 'b':
+                                       switch (argv[a][2])
+                                       {
+                                               case '1':
+                                                       bpd = 1;
+                                                       break;
+
+                                               case '2':
+                                                       bpd = 2;
+                                                       break;
+
+                                               case '4':
+                                                       bpd = 4;
+                                                       break;
+
+                                               default:
+                                                       UnknownFlag(argv[a]);
+                                       }
+                                       break;
+
+                                       // Produce an header
+                               case 'h':
+                                       header = 1;
+                                       break;
+
+                                       // New line each n line
+                               case 'l':
+                                       switch (argv[a][2])
+                                       {
+                                               case 'b':
+                                                       lb = atoi(argv[++a]);
+                                                       break;
+
+                                               default:
+                                                       UnknownFlag(argv[a]);
+                                       }
+
+                                       // Number of bit per line
+                               case 'n':
+                                       nbCol = atoi(argv[++a]);
+                                       break;
+
+                                       // Skip bytes
+                               case 's':
+                                       switch (argv[a][2])
+                                       {
+                                                       // Beginig of file
+                                               case 's':
+                                                       SkeepStart = atoi(argv[++a]);
+                                                       break;
+
+                                                       // End of file
+                                               case 'e':
+                                                       SkeepEnd = atoi(argv[++a]);
+                                                       break;
+
+                                                       // Flag inconnu
+                                               default:
+                                                       UnknownFlag(argv[a]);
+                                       }
+
+                                       // Flag inconnu
+                               default:
+                                       UnknownFlag(argv[a]);
+                       }
+               }
+               // A filename
+               else
+               {
+                       if (iFileName == NULL)
+                       {
+                               iFileName = argv[a];
+                               if ((inFile = fopen(iFileName, "rb")) == NULL)
+                               {
+                                       fprintf(stderr, "Error: can't open %s\n", iFileName);
+                                       exit(EXIT_FAILURE);
+                               }
+                       }
+                       else
+                       {
+                               if (oFileName == NULL)
+                               {
+                                       oFileName = argv[a];
+                                       if ((outFile = fopen(oFileName, "wb")) == NULL)
+                                       {
+                                               fprintf(stderr, "Error: can't open %s\n", oFileName);
+                                               exit(EXIT_FAILURE);
+                                       }
+                               }
+                               else
+                               {
+                                       fprintf(stderr, "Error: Too many filesnames given!\n");
+                                       help();
+                                       exit(EXIT_FAILURE);
+                               }
+                       }
+               }
+       }
+
+       if (!iFileName)
+               exit(EXIT_FAILURE);
+
+       // Get file informations
+       if (stat(iFileName, &st) != 0)
+       {
+               fprintf(stderr, "Error: when scanning file %s\n", argv[1]);
+               exit(EXIT_FAILURE);
+       }
+
+       // Allocating memory
+       if (!(memory = malloc(st.st_size + 3)))
+       {
+               memset(memory, 0, st.st_size + 3);
+               fprintf(stderr, "Error: not enought memory\n");
+               exit(EXIT_FAILURE);
+       }
+
+       // Reading the file
+       if (fread(memory, 1, st.st_size, inFile) != (size_t)st.st_size)
+       {
+               fprintf(stderr, "Error: when reading file %s\n", argv[1]);
+               fclose(inFile);
+               exit(EXIT_FAILURE);
+       }
+       fclose(inFile);
+
+       // Must produce an header
+       if (header)
+       {
+               unsigned int i;
+               char hFileName[256], *def = NULL;
+               FILE *hFile = stdout;
+
+               if (oFileName)
+               {
+                       strcpy(hFileName, oFileName);
+                       hFileName[strlen(hFileName) - 1] = 'h';
+                       hFile = fopen(hFileName, "wt");
+               }
+
+               WriteHeader(hFile, hFileName, iFileName);
+
+               // Replace all '.' by '_'
+               for (i = 0; i < strlen(hFileName); i++)
+                       if (hFileName[i] == '.')
+                               hFileName[i] = '_';
+                       else
+                               hFileName[i] = toupper(hFileName[i]);
+
+               // the #ifdef at the begining
+               def = strrchr(hFileName, '/');
+               def = def ? def + 1 : hFileName;
+               fprintf(hFile, "#ifndef __%s__\n#define __%s__\n\n", def, def);
+
+               // Define array size
+               fprintf(hFile, "#define _%s_size_ %u\n\n", arrayName, (unsigned int) (st.st_size - SkeepStart - SkeepEnd) / bpd);
+
+               // Begin the array
+               fprintf(hFile, "extern unsigned ");
+               fprintf(hFile, "%s ", bpd == 1 ? "char" : bpd == 2 ? "short" : "long");
+               fprintf(hFile, "%s[", arrayName);
+               fprintf(hFile, "%u];\n\n", (unsigned int) (st.st_size - SkeepStart - SkeepEnd) / bpd);
+
+               // the #endif at the end
+               fprintf(hFile, "#endif\n\n");
+
+               if (oFileName)
+                       fclose(hFile);
+       }
+
+       WriteHeader(outFile, oFileName, iFileName);
+
+       // Define array size
+       if (!header)
+               fprintf(outFile, "#define _%s_size_ %u\n\n", arrayName, (unsigned int) (st.st_size - SkeepStart - SkeepEnd) / bpd);
+
+       // Begin the array
+       fprintf(outFile, "unsigned ");
+       fprintf(outFile, "%s ", bpd == 1 ? "char" : bpd == 2 ? "short" : "long");
+       fprintf(outFile, "%s[", arrayName);
+       fprintf(outFile, "%u] = {\n\t", (unsigned int) (st.st_size - SkeepStart - SkeepEnd) / bpd);
+
+       // Writing file elements
+       for (i = 0; i < (st.st_size - SkeepEnd - SkeepStart) / bpd; /*i+=bpd */ i++)
+       {
+               // We write an item of bpd byte(s)
+               switch (bpd)
+               {
+                       case 1:
+                               fprintf(outFile, "0x%02x", *(unsigned char *) &memory[SkeepStart + i]);
+                               break;
+
+                       case 2:
+                               fprintf(outFile, "0x%04x", *(unsigned short *) &memory[SkeepStart + i]);
+                               break;
+
+                       case 4:
+                               fprintf(outFile, "0x%08lx", *(unsigned long *) &memory[SkeepStart + i]);
+                               break;
+               }
+
+               // Must put a coma ?
+               if (i != st.st_size - 1)
+                       fprintf(outFile, ",");
+
+               // End of a line ?
+               if (i && !((i + 1) % nbCol))
+               {
+                       // -lb option
+                       if (lb && !((++nbLine) % lb))
+                               fprintf(outFile, "\n");
+                       fprintf(outFile, "\n\t");
+               }
+               // Add a space
+               else
+                       fprintf(outFile, " ");
+       }
+
+       // The last line as nbCol elements
+       if (((st.st_size - SkeepStart - SkeepEnd) / bpd) % nbCol)
+               fprintf(outFile, "\n");
+
+       // Close the array
+       fprintf(outFile, "};\n");
+
+       // CLose the output file
+       if (outFile != stdout)
+               fclose(outFile);
+
+       // Free allocated memory
+       free(memory);
+
+       exit(EXIT_SUCCESS);
+}
diff --git a/tools/misc/mbootpack/bootsect.S b/tools/misc/mbootpack/bootsect.S
new file mode 100644 (file)
index 0000000..2cc9ee1
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ *  bootsect.S
+ *
+ *  This is bootsect.S from the linux 2.6.9 sources,
+ *  with minor changes for mbootpack.
+ *
+ *  
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License as
+ *  published by the Free Software Foundation; either version 2 of the
+ *  License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ *  02111-1307, USA.
+ *
+ * $Id: bootsect.S,v 1.2 2005/03/23 10:39:11 tjd21 Exp $
+ *
+ */
+       
+#include "mbootpack.h"
+               
+/*
+ *     bootsect.S              Copyright (C) 1991, 1992 Linus Torvalds
+ *
+ *     modified by Drew Eckhardt
+ *     modified by Bruce Evans (bde)
+ *     modified by Chris Noe (May 1999) (as86 -> gas)
+ *     gutted by H. Peter Anvin (Jan 2003)
+ *
+ * BIG FAT NOTE: We're in real mode using 64k segments.  Therefore segment
+ * addresses must be multiplied by 16 to obtain their respective linear
+ * addresses. To avoid confusion, linear addresses are written using leading
+ * hex while segment addresses are written as segment:offset.
+ *
+ */
+/* #include <asm/boot.h> */
+/* Definitions we should have got from there */        
+#define DEF_INITSEG     0x9000
+#define DEF_SYSSEG      0x1000
+#define DEF_SETUPSEG    0x9020
+#define DEF_SYSSIZE     0x7F00
+#define NORMAL_VGA      0xffff
+#define EXTENDED_VGA    0xfffe
+#define ASK_VGA         0xfffd
+
+
+/* SETUPSECTS  = 4 */                  /* default nr of setup-sectors */
+BOOTSEG                = 0x07C0                /* original address of boot-sector */
+INITSEG                = DEF_INITSEG           /* we move boot here - out of the way */
+SETUPSEG       = DEF_SETUPSEG          /* setup starts here */
+SYSSEG         = DEF_SYSSEG            /* system loaded at 0x10000 (65536) */
+SYSSIZE                = DEF_SYSSIZE           /* system size: # of 16-byte clicks */
+                                       /* to be loaded */
+ROOT_DEV       = 0                     /* ROOT_DEV is now written by "build" */
+SWAP_DEV       = 0                     /* SWAP_DEV is now written by "build" */
+
+#ifndef SVGA_MODE
+/* #define SVGA_MODE ASK_VGA */
+#define SVGA_MODE NORMAL_VGA
+#endif
+
+#ifndef RAMDISK
+#define RAMDISK 0
+#endif
+
+#ifndef ROOT_RDONLY
+#define ROOT_RDONLY 1
+#endif
+
+.code16
+.text
+
+.global _start
+_start:
+
+       # Normalize the start address
+       jmpl    $BOOTSEG, $start2
+
+start2:
+       movw    %cs, %ax
+       movw    %ax, %ds
+       movw    %ax, %es
+       movw    %ax, %ss
+       movw    $0x7c00, %sp
+       sti
+       cld
+
+       movw    $bugger_off_msg, %si
+
+msg_loop:
+       lodsb
+       andb    %al, %al
+       jz      die
+       movb    $0xe, %ah
+       movw    $7, %bx
+       int     $0x10
+       jmp     msg_loop
+
+die:
+       # Allow the user to press a key, then reboot
+       xorw    %ax, %ax
+       int     $0x16
+       int     $0x19
+
+       # int 0x19 should never return.  In case it does anyway,
+       # invoke the BIOS reset code...
+       ljmp    $0xf000,$0xfff0
+
+
+bugger_off_msg:
+       .ascii  "Direct booting from floppy is no longer supported.\r\n"
+       .ascii  "Please use a boot loader program instead.\r\n"
+       .ascii  "\n"
+       .ascii  "Remove disk and press any key to reboot . . .\r\n"
+       .byte   0
+       
+
+       # Kernel attributes; used by setupbegtext
+
+       .org 497
+setup_sects:   .byte SETUPSECTS
+root_flags:    .word ROOT_RDONLY
+syssize:       .word SYSSIZE
+swap_dev:      .word SWAP_DEV
+ram_size:      .word RAMDISK
+vid_mode:      .word SVGA_MODE
+root_dev:      .word ROOT_DEV
+boot_flag:     .word 0xAA55
diff --git a/tools/misc/mbootpack/buildimage.c b/tools/misc/mbootpack/buildimage.c
new file mode 100644 (file)
index 0000000..2231728
--- /dev/null
@@ -0,0 +1,174 @@
+/*
+ *  buildimage.c
+ *
+ *  Takes the memory image of a loaded kernel and modules and repackages 
+ *  it as a linux bzImage
+ *
+ *  Copyright (C) 2003-2004  Tim Deegan (tjd21@cl.cam.ac.uk)
+ * 
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License as
+ *  published by the Free Software Foundation; either version 2 of the
+ *  License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ *  02111-1307, USA.
+ *
+ * $Id: buildimage.c,v 1.2 2005/03/23 10:39:19 tjd21 Exp $
+ *
+ */
+
+
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <getopt.h>
+#include <elf.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <asm/page.h>
+
+#include "mbootpack.h"
+#include "mb_header.h"
+
+/*  We will build an image that a bzImage-capable bootloader will load like 
+ *  this:
+ * 
+ *  ==============   (0)
+ *  (BIOS memory)
+ *  --------------
+ *  (Bootloader)
+ *  --------------
+ *  bzImage startup code
+ *  MBI, command-lines, module info
+ *  ==============   (0xa0000)
+ *  (memory hole)
+ *  ==============   (0x100000)
+ *  Kernel and modules
+ *  ==============
+ * 
+ *  The bzImage startup code is mostly taken straight from the linux kernel
+ *  (see bootsect.S, startup.S).  It does the usual unpleasant start-of-day
+ *  tasks to get to 32-bit protected mode, then sets registers appropriately 
+ *  and jumps to the kernel's entry address.
+ *  
+ *  It also does some relocation to make sure the MBI is where we expect it, 
+ *  and parses the linux command line.
+ */
+
+#define BZ_SETUP_OFFSET    (512 * (1 + SETUPSECTS)) 
+#define BZ_ENTRY_OFFSET    0x30
+#define BZ_MBI_OFFSET      0x34
+/* These *MUST* fit the offsets of entry_address and mbi_address in setup.S */
+
+/* Bring in the bzImage boot sector and setup code */
+#include "bzimage_header.c"
+
+address_t place_mbi(long int size) 
+/* Find space at the top of *low* memory for the MBI and associated red tape */
+{
+    address_t start;
+    start = 0xa000 - size;
+    if (start < 0x9000 + sizeof(bzimage_bootsect) + sizeof(bzimage_setup)) {
+        printf("Fatal: command-lines too long: need %i, have %i bytes\n",
+               size, 
+               0x1000 - (sizeof(bzimage_bootsect) + sizeof(bzimage_setup)));
+        exit(1);        
+    }
+    if (!quiet) {
+        printf("Placed MBI and strings (%p+%p)\n", 
+               start, size);
+    }
+    return start;
+}
+
+void make_bzImage(section_t *sections, 
+                  address_t entry, 
+                  address_t mbi,
+                  FILE *fp)
+/* Rework this list of sections into a bzImage and write it out to fp */
+{
+    int i;
+    size_t offset;
+    section_t *s;
+
+    /* Patch the kernel and mbi addresses into the setup code */
+    *(address_t *)(bzimage_setup + BZ_ENTRY_OFFSET) = entry;
+    *(address_t *)(bzimage_setup + BZ_MBI_OFFSET) = mbi;
+    if (!quiet) printf("Kernel entry is %p, MBI is %p.\n", entry, mbi);
+
+    /* Write out header and trampoline */
+    if (fseek(fp, 0, SEEK_SET) < 0) {
+        printf("Fatal: error seeking in output file: %s\n", 
+               strerror(errno));
+        exit(1);
+    }
+    if (fwrite(bzimage_bootsect, sizeof(bzimage_bootsect), 1, fp) != 1) {
+        printf("Fatal: error writing to output file: %s\n", 
+               strerror(errno));
+        exit(1);
+    }
+    if (fwrite(bzimage_setup, sizeof(bzimage_setup), 1, fp) != 1) {
+        printf("Fatal: error writing to output file: %s\n", 
+               strerror(errno));
+        exit(1);
+    }
+
+    if (!quiet) printf("Wrote bzImage header: %i + %i bytes.\n", 
+                       sizeof(bzimage_bootsect), sizeof(bzimage_setup));
+
+    /* Sorted list of sections below 1MB: write them out */
+    for (s = sections, i = 0; s; s = s->next) {
+        if (s->start >= HIGHMEM_START) continue;
+        offset = (s->start - 0x9000);
+        if (fseek(fp, offset, SEEK_SET) < 0) {
+            printf("Fatal: error seeking in output file: %s\n", 
+                   strerror(errno));
+            exit(1);
+        }
+        if (fwrite(s->buffer, s->size, 1, fp) != 1) {
+            printf("Fatal: error writing to output file: %s\n", 
+                   strerror(errno));
+            exit(1);
+        }
+        i++;
+    }
+
+    if (!quiet) printf("Wrote %i low-memory sections.\n", i);
+
+    /* Sorted list of sections higher than 1MB: write them out */
+    for (s = sections, i = 0; s; s = s->next) {
+        if (s->start < HIGHMEM_START) continue;
+        offset = (s->start - HIGHMEM_START) + BZ_SETUP_OFFSET;
+        if (fseek(fp, offset, SEEK_SET) < 0) {
+            printf("Fatal: error seeking in output file: %s\n", 
+                   strerror(errno));
+            exit(1);
+        }
+        if (fwrite(s->buffer, s->size, 1, fp) != 1) {
+            printf("Fatal: error writing to output file: %s\n", 
+                   strerror(errno));
+            exit(1);
+        }
+        i++;
+    }
+    
+    if (!quiet) printf("Wrote %i high-memory sections.\n", i);
+}
+
+
+/*
+ *  EOF(buildimage.c)
+ */
diff --git a/tools/misc/mbootpack/mb_header.h b/tools/misc/mbootpack/mb_header.h
new file mode 100644 (file)
index 0000000..2193457
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2000   Free Software Foundation, Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ *  MultiBoot Header description
+ */
+
+struct multiboot_header
+{
+  /* Must be MULTIBOOT_MAGIC - see below.  */
+  unsigned magic;
+  
+  /* Feature flags - see below.  */
+  unsigned flags;
+  
+  /*
+   * Checksum
+   *
+   * The above fields plus this one must equal 0 mod 2^32.
+   */
+  unsigned checksum;
+  
+  /* These are only valid if MULTIBOOT_AOUT_KLUDGE is set.  */
+  unsigned header_addr;
+  unsigned load_addr;
+  unsigned load_end_addr;
+  unsigned bss_end_addr;
+  unsigned entry_addr;
+
+  /* These are only valid if MULTIBOOT_VIDEO_MODE is set.  */
+  unsigned mode_type;
+  unsigned width;
+  unsigned height;
+  unsigned depth;
+};
+
+/*
+ * The entire multiboot_header must be contained
+ * within the first MULTIBOOT_SEARCH bytes of the kernel image.
+ */
+#define MULTIBOOT_SEARCH               8192
+#define MULTIBOOT_FOUND(addr, len) \
+  (! ((addr) & 0x3) \
+   && (len) >= 12 \
+   && *((int *) (addr)) == MULTIBOOT_MAGIC \
+   && ! (*((unsigned *) (addr)) + *((unsigned *) (addr + 4)) \
+        + *((unsigned *) (addr + 8))) \
+   && (! (MULTIBOOT_AOUT_KLUDGE & *((int *) (addr + 4))) || (len) >= 32) \
+   && (! (MULTIBOOT_VIDEO_MODE & *((int *) (addr + 4))) || (len) >= 48))
+
+/* Magic value identifying the multiboot_header.  */
+#define MULTIBOOT_MAGIC                        0x1BADB002
+
+/*
+ * Features flags for 'flags'.
+ * If a boot loader sees a flag in MULTIBOOT_MUSTKNOW set
+ * and it doesn't understand it, it must fail.
+ */
+#define MULTIBOOT_MUSTKNOW             0x0000FFFF
+
+/* currently unsupported flags...  this is a kind of version number.  */
+#define MULTIBOOT_UNSUPPORTED          0x0000FFF8
+
+/* Align all boot modules on i386 page (4KB) boundaries.  */
+#define MULTIBOOT_PAGE_ALIGN           0x00000001
+
+/* Must pass memory information to OS.  */
+#define MULTIBOOT_MEMORY_INFO          0x00000002
+
+/* Must pass video information to OS.  */
+#define MULTIBOOT_VIDEO_MODE           0x00000004
+
+/* This flag indicates the use of the address fields in the header.  */
+#define MULTIBOOT_AOUT_KLUDGE          0x00010000
diff --git a/tools/misc/mbootpack/mb_info.h b/tools/misc/mbootpack/mb_info.h
new file mode 100644 (file)
index 0000000..fb37f10
--- /dev/null
@@ -0,0 +1,217 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2000  Free Software Foundation, Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ *  The structure type "mod_list" is used by the "multiboot_info" structure.
+ */
+
+struct mod_list
+{
+  /* the memory used goes from bytes 'mod_start' to 'mod_end-1' inclusive */
+  unsigned long mod_start;
+  unsigned long mod_end;
+  
+  /* Module command line */
+  unsigned long cmdline;
+  
+  /* padding to take it to 16 bytes (must be zero) */
+  unsigned long pad;
+};
+
+
+/*
+ *  INT-15, AX=E820 style "AddressRangeDescriptor"
+ *  ...with a "size" parameter on the front which is the structure size - 4,
+ *  pointing to the next one, up until the full buffer length of the memory
+ *  map has been reached.
+ */
+
+struct AddrRangeDesc
+{
+  unsigned long size;
+  unsigned long long BaseAddr;
+  unsigned long long Length;
+  unsigned long Type;
+  
+  /* unspecified optional padding... */
+};
+
+/* usable memory "Type", all others are reserved.  */
+#define MB_ARD_MEMORY          1
+
+
+/* Drive Info structure.  */
+struct drive_info
+{
+  /* The size of this structure.  */
+  unsigned long size;
+
+  /* The BIOS drive number.  */
+  unsigned char drive_number;
+
+  /* The access mode (see below).  */
+  unsigned char drive_mode;
+
+  /* The BIOS geometry.  */
+  unsigned short drive_cylinders;
+  unsigned char drive_heads;
+  unsigned char drive_sectors;
+
+  /* The array of I/O ports used for the drive.  */
+  unsigned short drive_ports[0];
+};
+
+/* Drive Mode.  */
+#define MB_DI_CHS_MODE         0
+#define MB_DI_LBA_MODE         1
+
+
+/* APM BIOS info.  */
+struct apm_info
+{
+  unsigned short version;
+  unsigned short cseg;
+  unsigned long offset;
+  unsigned short cseg_16;
+  unsigned short dseg_16;
+  unsigned short cseg_len;
+  unsigned short cseg_16_len;
+  unsigned short dseg_16_len;
+};
+
+
+/*
+ *  MultiBoot Info description
+ *
+ *  This is the struct passed to the boot image.  This is done by placing
+ *  its address in the EAX register.
+ */
+
+struct multiboot_info
+{
+  /* MultiBoot info version number */
+  unsigned long flags;
+  
+  /* Available memory from BIOS */
+  unsigned long mem_lower;
+  unsigned long mem_upper;
+  
+  /* "root" partition */
+  unsigned long boot_device;
+  
+  /* Kernel command line */
+  unsigned long cmdline;
+  
+  /* Boot-Module list */
+  unsigned long mods_count;
+  unsigned long mods_addr;
+  
+  union
+  {
+    struct
+    {
+      /* (a.out) Kernel symbol table info */
+      unsigned long tabsize;
+      unsigned long strsize;
+      unsigned long addr;
+      unsigned long pad;
+    }
+    a;
+    
+    struct
+    {
+      /* (ELF) Kernel section header table */
+      unsigned long num;
+      unsigned long size;
+      unsigned long addr;
+      unsigned long shndx;
+    }
+    e;
+  }
+  syms;
+  
+  /* Memory Mapping buffer */
+  unsigned long mmap_length;
+  unsigned long mmap_addr;
+  
+  /* Drive Info buffer */
+  unsigned long drives_length;
+  unsigned long drives_addr;
+  
+  /* ROM configuration table */
+  unsigned long config_table;
+  
+  /* Boot Loader Name */
+  unsigned long boot_loader_name;
+
+  /* APM table */
+  unsigned long apm_table;
+
+  /* Video */
+  unsigned long vbe_control_info;
+  unsigned long vbe_mode_info;
+  unsigned short vbe_mode;
+  unsigned short vbe_interface_seg;
+  unsigned short vbe_interface_off;
+  unsigned short vbe_interface_len;
+};
+
+/*
+ *  Flags to be set in the 'flags' parameter above
+ */
+
+/* is there basic lower/upper memory information? */
+#define MB_INFO_MEMORY                 0x00000001
+/* is there a boot device set? */
+#define MB_INFO_BOOTDEV                        0x00000002
+/* is the command-line defined? */
+#define MB_INFO_CMDLINE                        0x00000004
+/* are there modules to do something with? */
+#define MB_INFO_MODS                   0x00000008
+
+/* These next two are mutually exclusive */
+
+/* is there a symbol table loaded? */
+#define MB_INFO_AOUT_SYMS              0x00000010
+/* is there an ELF section header table? */
+#define MB_INFO_ELF_SHDR               0x00000020
+
+/* is there a full memory map? */
+#define MB_INFO_MEM_MAP                        0x00000040
+
+/* Is there drive info?  */
+#define MB_INFO_DRIVE_INFO             0x00000080
+
+/* Is there a config table?  */
+#define MB_INFO_CONFIG_TABLE           0x00000100
+
+/* Is there a boot loader name?  */
+#define MB_INFO_BOOT_LOADER_NAME       0x00000200
+
+/* Is there a APM table?  */
+#define MB_INFO_APM_TABLE              0x00000400
+
+/* Is there video information?  */
+#define MB_INFO_VIDEO_INFO             0x00000800
+
+/*
+ *  The following value must be present in the EAX register.
+ */
+
+#define MULTIBOOT_VALID                        0x2BADB002
diff --git a/tools/misc/mbootpack/mbootpack.c b/tools/misc/mbootpack/mbootpack.c
new file mode 100644 (file)
index 0000000..42a3151
--- /dev/null
@@ -0,0 +1,703 @@
+/*
+ *  mbootpack.c
+ *
+ *  Takes a multiboot image, command-line and modules, and repackages
+ *  them as if they were a linux kernel.   Only supports a subset of 
+ *  the multiboot info page options (enough to boot the Xen hypervisor).
+ *
+ *  Copyright (C) 2003-2004  Tim Deegan (tjd21@cl.cam.ac.uk)
+ * 
+ *  Parts based on GNU GRUB, Copyright (C) 2000  Free Software Foundation, Inc
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License as
+ *  published by the Free Software Foundation; either version 2 of the
+ *  License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ *  02111-1307, USA.
+ *
+ * $Id: mbootpack.c,v 1.3 2005/03/23 10:38:36 tjd21 Exp tjd21 $
+ *
+ */
+
+#define _GNU_SOURCE
+#include "mbootpack.h"
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <getopt.h>
+#include <elf.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <asm/page.h>
+
+/* From GNU GRUB */
+#include "mb_header.h"
+#include "mb_info.h"
+
+
+/*
+ *  The plan: Marshal up the multiboot modules and strings as if we 
+ *  were loading them into memory on a fresh ix86 PC.  Attach 
+ *  a linux bzImage header to the front, which sets up the machine
+ *  appropriately and then jumps to the kernel entry address.
+ * 
+ *  The memory map will be made up roughly like so:
+ *
+ *  =============
+ *  multiboot information (mbi) struct
+ *  -------
+ *  kernel command line
+ *  -------
+ *  bootloader name
+ *  -------
+ *  module command lines
+ *  -------
+ *  module information structs
+ *  =============
+ *   (memory hole)
+ *  =============
+ *  kernel
+ *  -------------
+ *  module 1
+ *  -------------
+ *  module 2
+ *  -------------
+ *      .
+ *      .
+ *      .
+ *
+ *  ==============
+ * 
+ * 
+ *  For allocation of memory we assume that the target machine has 'low'
+ *  memory from 0 to 640K and 'high' memory starting at 1M.  We allocate
+ *  the kernel first, wherever it wants to be.  After that, sections
+ *  are added at the next available aligned address, always in the order
+ *  given above, and skipping the memory hole at 640K.  Allocated sections 
+ *  are stored in a linked list of buffers.
+ * 
+ *  Re-packaging as a bzImage file happens in buildimage.c
+ *  
+ */
+
+/* Version */
+static const char version_string[] = "mbootpack " MBOOTPACK_VERSION_STRING;
+
+/* Flags */
+int quiet = 0;
+
+/* How much of the start of a kernel we read looking for headers.  
+ * Must be >= MULTIBOOT_SEARCH */
+#define HEADERBUF_SIZE MULTIBOOT_SEARCH
+
+
+/* Linked list of loaded sections, and a pointer to the next 
+ * available space (i.e. just above the highest allocation so far). */
+static section_t *sections = NULL;
+static section_t *last_section = NULL;
+static address_t next_free_space = 0; 
+
+static void usage(void)
+/* If we don't understand the command-line options */ 
+{
+    printf(
+"Usage: mbpack [OPTIONS] kernel-image\n\n"
+"  -h --help                       Print this text.\n"
+"  -q --quiet                      Only output errors and warnings.\n"
+"  -o --output=filename            Output to filename (default \"bzImage\").\n"
+"  -M --multiboot-output           Produce a multiboot kernel, not a bzImage\n"
+"                                  (sets default output file to \"mbImage\").\n"
+"  -c --command-line=STRING        Set the kernel command line (DEPRECATED!).\n"
+"  -m --module=\"MOD arg1 arg2...\"  Load module MOD with arguments \"arg1...\"\n"
+"                                  (can be used multiple times).\n"
+"\n");
+    exit(1);
+}
+
+
+static void place_kernel_section(address_t start, long int size)
+/* Place the kernel in memory, checking for the memory hole. */
+{
+    if (start >= MEM_HOLE_END) {
+        /* Above the memory hole: easy */
+        next_free_space = MAX(next_free_space, start + size);
+        if (!quiet) {
+            printf("Placed kernel section (%p+%p)\n", start, size);
+        }
+        return;
+    }
+    
+    if (start >= MEM_HOLE_START) {
+        /* In the memory hole.  Not so good */
+        printf("Fatal: kernel load address (%p) is in the memory hole.\n",
+               start);
+        exit(1);
+    }
+    
+    if (start + size > MEM_HOLE_START) {
+        /* Too big for low memory */
+        printf("Fatal: kernel (%p+%p) runs into the memory hole.\n",
+               start, size);
+        exit(1);
+    }  
+    
+    /* Kernel loads below the memory hole */
+    next_free_space = MAX(next_free_space, start + size);
+
+    if (!quiet) {
+        printf("Placed kernel section (%p+%p)\n", start, size);
+    }
+}
+
+
+static address_t place_section(long int size, int align)
+/* Find the next available place for this section.  
+ * "align" must be a power of 2 */
+{
+    address_t start;
+    assert(next_free_space != 0);
+    assert(((~align + 1) & align) == align);
+
+    start = ROUNDUP_P2(next_free_space, align);
+
+    /* Check that we don't hit the memory hole */
+    if (start < MEM_HOLE_END && (start + size) > MEM_HOLE_START) 
+        start = ROUNDUP_P2(MEM_HOLE_END, align);
+
+    next_free_space = start + size;
+
+    if (!quiet) {
+        printf("Placed section (%p+%p), align=%p\n", 
+               start, size, align);
+    }
+    return start;
+}
+
+
+
+
+static address_t load_kernel(const char *filename)
+/* Load an elf32/multiboot kernel from this file 
+ * Returns the entry address for the kernel. */
+{
+    unsigned int i;
+    address_t start;
+    size_t len;
+    long int size, loadsize;
+    FILE *fp;    
+    char *buffer;
+    section_t *sec, *s;
+    Elf32_Ehdr *ehdr;
+    Elf32_Phdr *phdr;
+    struct multiboot_header *mbh;
+    struct stat sb;
+
+    static char headerbuf[HEADERBUF_SIZE];
+
+    /* Stat and open the file */
+    if (stat(filename, &sb) != 0) {
+        printf("Fatal: cannot stat %s: %s\n", filename, strerror(errno));
+        exit(1);
+    }
+    if ((fp = fopen(filename, "r")) == NULL) {
+        printf("Fatal: cannot open %s: %s\n", filename, strerror(errno));
+        exit(1);
+    }
+    
+    /* Load the first 8k of the file */
+    if (fseek(fp, 0, SEEK_SET) < 0) {
+        printf("Fatal: seek error in %s: %s\n", filename, strerror(errno));
+        exit(1);
+    }
+    if ((len = fread(headerbuf, 1, HEADERBUF_SIZE, fp))
+        < HEADERBUF_SIZE)
+    {
+        if (feof(fp))   /* Short file */
+        {
+            if (len < 12) {
+                printf("Fatal: %s is too short to be a multiboot file.", 
+                       filename);
+                exit(1);
+            }
+        } else {
+            printf("Fatal: read error in %s: %s\n", filename, strerror(errno));
+            exit(1);
+        }
+    }
+
+    /* Sanity-check: is this file compressed? */
+    if ((headerbuf[0] == '\037' && 
+         (headerbuf[1] == '\235' /* .Z */ ||
+          headerbuf[1] == '\213' /* .gz */)) ||
+        (headerbuf[0] == 'B' && headerbuf[1] == 'Z') /* .bz[2] */) {
+        printf("Warning: %s looks like a compressed file.\n"
+               "         You should uncompress it first!\n", filename);
+    }
+    
+    /* Now look for a multiboot header */
+    for (i = 0; i <= MIN(len - 12, MULTIBOOT_SEARCH - 12); i += 4)
+    {
+        mbh = (struct multiboot_header *)(headerbuf + i);
+        if (mbh->magic != MULTIBOOT_MAGIC 
+            || ((mbh->magic+mbh->flags+mbh->checksum) & 0xffffffff))
+        {
+            /* Not a multiboot header */
+            continue;
+        }
+        if (mbh->flags & MULTIBOOT_UNSUPPORTED) {
+            /* Requires options we don't support */
+            printf("Fatal: found a multiboot header, but it "
+                    "requires multiboot options that I\n"
+                    "don't understand.  Sorry.\n");
+            exit(1);
+        } 
+        if (mbh->flags & MULTIBOOT_VIDEO_MODE) { 
+            /* Asked for screen mode information */
+            /* XXX carry on regardless */
+            printf("Warning: found a multiboot header which asks "
+                   "for screen mode information.\n"
+                   "         This kernel will NOT be given valid"
+                   "screen mode information at boot time.\n");
+        }
+        /* This kernel will do: place and load it */
+
+        if (mbh->flags & MULTIBOOT_AOUT_KLUDGE) {
+
+            /* Load using the offsets in the multiboot header */
+            if(!quiet) 
+                printf("Loading %s using multiboot header.\n", filename);
+
+            /* How much is there? */
+            start = mbh->load_addr;            
+            if (mbh->load_end_addr != 0) 
+                loadsize = mbh->load_end_addr - mbh->load_addr;
+            else 
+                loadsize = sb.st_size;
+            
+            /* How much memory will it take up? */ 
+            if (mbh->bss_end_addr != 0)
+                size = mbh->bss_end_addr - mbh->load_addr;
+            else
+                size = loadsize;
+            
+            if (loadsize > size) {
+                printf("Fatal: can't load %i bytes of kernel into %i bytes " 
+                       "of memory.\n", loadsize, size);
+                exit(1);
+            }
+
+            /* Does it fit where it wants to be? */
+            place_kernel_section(start, size);            
+            
+            /* Load the kernel */
+            if ((buffer = malloc(size)) == NULL) {
+                printf("Fatal: malloc() for kernel load failed: %s\n",
+                       strerror(errno));
+                exit(1);
+            }
+            if ((fread(buffer, loadsize, 1, fp)) != 1) { 
+                printf("Fatal: cannot read %s: %s\n", 
+                       filename, strerror(errno));
+                exit(1);
+            }
+            fclose(fp);
+            
+            /* Clear the kernel BSS */
+            memset(buffer + loadsize, 0, size - loadsize);
+
+            /* Start off the linked list of sections */
+            if ((sec = (section_t *)malloc(sizeof (section_t))) == NULL) {
+                printf("Fatal: malloc() for section_t failed: %s\n",
+                       strerror(errno));
+                exit(1);
+            }
+            sec->buffer = buffer;
+            sec->start = start;
+            sec->size = size;
+            sec->next = NULL;
+            sec->prev = NULL;
+            sections = sec;
+            last_section = sec;
+            
+            /* Done. */
+            if (!quiet) printf("Loaded kernel from %s\n", filename);
+            return mbh->entry_addr;
+            
+        } else {
+
+            /* Now look for an ELF32 header */    
+            ehdr = (Elf32_Ehdr *)headerbuf;
+            if (*(unsigned long *)ehdr != 0x464c457f 
+                || ehdr->e_ident[EI_DATA] != ELFDATA2LSB
+                || ehdr->e_ident[EI_CLASS] != ELFCLASS32
+                || ehdr->e_machine != EM_386)
+            {
+                printf("Fatal: kernel has neither ELF32/x86 nor multiboot load"
+                       " headers.\n");
+                exit(1);
+            }
+            if (ehdr->e_phoff + ehdr->e_phnum*sizeof(*phdr) > HEADERBUF_SIZE) {
+                /* Don't expect this will happen with sane kernels */
+                printf("Fatal: too much ELF for me.  Try increasing "
+                       "HEADERBUF_SIZE in mbootpack.\n");
+                exit(1);
+            }
+            if (ehdr->e_phoff + ehdr->e_phnum*sizeof (*phdr) > len) {
+                printf("Fatal: malformed ELF header overruns EOF.\n");
+                exit(1);
+            }
+            if (ehdr->e_phnum <= 0) {
+                printf("Fatal: ELF kernel has no program headers.\n");
+                exit(1);
+            }
+
+            if(!quiet) 
+                printf("Loading %s using ELF header.\n", filename);
+
+            if (ehdr->e_type != ET_EXEC 
+                || ehdr->e_version != EV_CURRENT
+                || ehdr->e_phentsize != sizeof (Elf32_Phdr)) {
+                printf("Warning: funny-looking ELF header.\n");
+            }
+            phdr = (Elf32_Phdr *)(headerbuf + ehdr->e_phoff);
+
+            /* Obey the program headers to load the kernel */
+            for(i = 0; i < ehdr->e_phnum; i++) {
+
+                start = phdr[i].p_paddr;
+                size = phdr[i].p_memsz;
+                if (phdr[i].p_type != PT_LOAD) 
+                    loadsize = 0;
+                else 
+                    loadsize = MIN((long int)phdr[i].p_filesz, size);
+
+                if ((buffer = malloc(size)) == NULL) {
+                    printf("Fatal: malloc() for kernel load failed: %s\n",
+                           strerror(errno));
+                    exit(1);
+                }
+
+                /* Place the section where it wants to be */
+                place_kernel_section(start, size);            
+
+                /* Load section from file */ 
+                if (loadsize > 0) {
+                    if (fseek(fp, phdr[i].p_offset, SEEK_SET) != 0) {
+                        printf("Fatal: seek failed in %s\n",
+                                strerror(errno));
+                        exit(1);
+                    }
+                    if ((fread(buffer, loadsize, 1, fp)) != 1) { 
+                        printf("Fatal: cannot read %s: %s\n", 
+                               filename, strerror(errno));
+                        exit(1);
+                    }
+                }
+
+                /* Clear the rest of the buffer */
+                memset(buffer + loadsize, 0, size - loadsize);
+
+                /* Add this section to the list (keeping it ordered) */
+                if ((sec = (section_t *)malloc(sizeof (section_t))) == NULL) {
+                    printf("Fatal: malloc() for section_t failed: %s\n",
+                           strerror(errno));
+                    exit(1);
+                }
+                sec->buffer = buffer;
+                sec->start = start;
+                sec->size = size;
+
+                for(s = sections; s; s = s->next) {
+                    if (s->start > start) {
+                        sec->next = s;
+                        if (s->prev == NULL) {
+                            /* sec becomes the new first item */
+                            s->prev = sec;
+                            sections = sec;
+                        } else {
+                            /* sec goes between s->prev and s */
+                            sec->prev = s->prev;
+                            sec->prev->next = sec;
+                            s->prev = sec;
+                        }
+                        break;
+                    }
+                }
+                if (s == NULL) {
+                    /* sec becomes the new last item */
+                    sec->next = NULL;
+                    sec->prev = last_section;
+                    if (last_section) {
+                        last_section->next = sec;
+                    } else {
+                        sections = sec;
+                    }
+                    last_section = sec;
+                }
+            }
+         
+            /* Done! */
+            if (!quiet) printf("Loaded kernel from %s\n", filename);
+            return ehdr->e_entry;
+        }
+
+    }
+
+    /* This is not a multiboot kernel */
+    printf("Fatal: %s is not a multiboot kernel.\n", filename);
+    exit(1);
+}
+
+
+
+
+int main(int argc, char **argv) 
+{
+    char *buffer, *imagename, *command_line, *p;
+    char *mod_filename, *mod_command_line, *mod_clp;
+    char *out_filename;
+    section_t *sec;
+    FILE *fp;
+    struct stat sb;
+    struct multiboot_info *mbi;
+    struct mod_list *modp;
+    address_t start, kernel_entry;
+    long int size, mod_command_line_space, command_line_len;
+    int modules, opt, mbi_reloc_offset, make_multiboot;
+
+    static const char short_options[] = "hc:m:o:qM";
+    static const struct option options[] = {
+        { "help",              0, 0, 'h' },
+        { "command-line",      1, 0, 'c' },
+        { "append",            1, 0, 'c' },
+        { "module",            1, 0, 'm' },
+        { "output",            1, 0, 'o' },
+        { "quiet",             0, 0, 'q' },
+        { 0,                   0, 0, 0 },
+    };
+
+    /* Parse the command line */
+    out_filename = NULL;
+    command_line = "";
+    command_line_len = 0;
+    modules = 0;
+    mod_command_line_space = 0;
+    while((opt = getopt_long(argc, argv, short_options, options, 0)) != -1)
+    {
+        switch(opt) {
+        case 'c':
+            command_line = optarg;
+            break;
+        case 'm':
+            modules++;
+            mod_command_line_space += strlen(optarg) + 1;
+            break;
+        case 'o':
+            out_filename = optarg;
+            break;
+        case 'q':
+            quiet = 1;
+            break;
+        case 'h':
+        case '?':
+        default:
+            usage();
+        }
+    }
+    imagename = argv[optind];
+    if (!imagename || strlen(imagename) == 0) usage();
+    command_line_len = strlen(command_line) + strlen(imagename) + 2;
+    /* Leave space to overwritethe command-line at boot time */
+    command_line_len = MAX(command_line_len, CMD_LINE_SPACE); 
+    if (!out_filename) out_filename = "bzImage";
+
+    /* Place and load the kernel */
+    kernel_entry = load_kernel(imagename);
+    assert(sections != NULL);
+    assert(last_section != NULL);
+    assert(next_free_space != 0);
+    
+    /* Next section is all the metadata between kernel and modules */
+    size = ((((sizeof (struct multiboot_info)
+               + command_line_len
+               + strlen(version_string) + 1
+               + mod_command_line_space) 
+              + 3 ) & ~3)
+            + modules * sizeof (struct mod_list));
+    /* Locate this section after the setup sectors, in *low* memory */
+    start = place_mbi(size);
+
+    if ((buffer = malloc(size)) == NULL) {
+        printf("Fatal: malloc() for boot metadata failed: %s\n",
+               strerror(errno));
+        exit(1);
+    }
+
+    if ((sec = (section_t *)malloc(sizeof (section_t))) == NULL) {
+        printf("Fatal: malloc() for section_t failed: %s\n",
+               strerror(errno));
+        exit(1);
+    }
+    sec->buffer = buffer;
+    sec->start = start;
+    sec->size = size;
+    sec->next = NULL;
+    sec->prev = last_section;
+    last_section->next = sec;
+    last_section = sec;
+
+    /* Multiboot info struct */
+    mbi = (struct multiboot_info *)buffer;
+    memset(buffer, 0, sizeof (struct multiboot_info));
+    mbi_reloc_offset = start - (address_t)buffer;
+    
+    /* Command line */
+    p = (char *)(mbi + 1);
+    sprintf(p, "%s %s", imagename, command_line);
+    mbi->cmdline = ((address_t)p) + mbi_reloc_offset;
+    p += command_line_len;
+
+    /* Bootloader ID */
+    sprintf(p, version_string);
+    mbi->boot_loader_name = ((address_t)p) + mbi_reloc_offset;
+    p += strlen(version_string) + 1;
+
+    /* Next is space for the module command lines */
+    mod_clp = p;
+
+    /* Last come the module info structs */
+    modp = (struct mod_list *)
+        ((((address_t)p + mod_command_line_space) + 3) & ~3);
+    mbi->mods_count = modules;
+    mbi->mods_addr = ((address_t)modp) + mbi_reloc_offset;
+
+    /* Memory information will be added at boot time, by setup.S 
+     * or trampoline.S. */
+    mbi->flags = MB_INFO_CMDLINE | MB_INFO_BOOT_LOADER_NAME;
+
+
+    /* Load the modules */
+    if (modules) {
+        mbi->flags |= MB_INFO_MODS;
+                
+        /* Go back and parse the module command lines */
+        optind = opterr = 1;
+        while((opt = getopt_long(argc, argv, 
+                                 short_options, options, 0)) != -1)
+        {
+            if (opt != 'm') continue;
+
+            /* Split module filename from command line */
+            mod_command_line = mod_filename = optarg;
+            if ((p = strchr(mod_filename, ' ')) != NULL) {
+                /* See as I discard the 'const' modifier */
+                *p = '\0';
+            }
+
+            /* Find space for it */
+            if (stat(mod_filename, &sb) != 0) {
+                printf("Fatal: cannot stat %s: %s\n",
+                       mod_filename, strerror(errno));
+                exit(1);
+            }
+            size = sb.st_size;
+            start = place_section(size, X86_PAGE_SIZE);
+            /* XXX should be place_section(size, 4) if the MBH hasn't got
+             * XXX MULTIBOOT_PAGE_ALIGN set, but that breaks Xen */
+
+            /* Load it */ 
+            if ((buffer = malloc(sb.st_size)) == NULL) {
+                printf("Fatal: malloc failed for module load: %s\n",
+                       strerror(errno));
+                exit(1);
+            }
+            if ((fp = fopen(mod_filename, "r")) == NULL) {
+                printf("Fatal: cannot open %s: %s\n",
+                       mod_filename, strerror(errno));
+                exit(1);
+            }
+            if ((fread(buffer, sb.st_size, 1, fp)) != 1) { 
+                printf("Fatal: cannot read %s: %s\n",
+                       mod_filename, strerror(errno));
+                exit(1);
+            }
+            fclose(fp);
+            
+            /* Sanity-check: is this file compressed? */
+            if ((buffer[0] == '\037' && 
+                 (buffer[1] == '\235' /* .Z */ ||
+                  buffer[1] == '\213' /* .gz */)) ||
+                (buffer[0] == 'B' && buffer[1] == 'Z') /* .bz[2] */) {
+                printf("Warning: %s looks like a compressed file.\n",
+                       mod_filename);
+            }
+
+            if (!quiet) printf("Loaded module from %s\n", mod_filename);
+
+            /* Restore the command line to its former glory */
+            if (p != NULL) *p = ' ';
+
+            /* Fill in the module info struct */
+            modp->mod_start = start;
+            modp->mod_end = start + size;
+            modp->cmdline = (address_t)mod_clp + mbi_reloc_offset;
+            modp->pad = 0;
+            modp++;
+
+            /* Store the module command line */
+            sprintf(mod_clp, "%s", mod_command_line);
+            mod_clp += strlen(mod_clp) + 1;
+
+            /* Add the section to the list */
+            if ((sec = (section_t *)malloc(sizeof (section_t))) == NULL) {
+                printf("Fatal: malloc() for section_t failed: %s\n",
+                       strerror(errno));
+                exit(1);
+            }
+            sec->buffer = buffer;
+            sec->start = start;
+            sec->size = size;
+            sec->next = NULL;
+            sec->prev = last_section;
+            last_section->next = sec;
+            last_section = sec;
+
+        }
+               
+    }
+    
+    /* Everything is placed and loaded.  Now we package it all up 
+     * as a bzImage */
+    if ((fp = fopen(out_filename, "w")) == NULL) {
+        printf("Fatal: cannot open %s: %s\n", out_filename, strerror(errno));
+        exit(1);
+    }
+    make_bzImage(sections, 
+                 kernel_entry, 
+                 ((address_t)mbi) + mbi_reloc_offset,
+                 fp);
+    fclose(fp);
+
+    /* Success! */
+    if(!quiet) printf("Finished.\n");
+    return 0;
+}
+
+/*
+ *  EOF (mbootpack.c)
+ */
+
diff --git a/tools/misc/mbootpack/mbootpack.h b/tools/misc/mbootpack/mbootpack.h
new file mode 100644 (file)
index 0000000..b28718b
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ *  mbootpack.h
+ *
+ *  Common definitions for mbootpack
+ * 
+ *  Copyright (C) 2003-2004  Tim Deegan (tjd21@cl.cam.ac.uk)
+ * 
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License as
+ *  published by the Free Software Foundation; either version 2 of the
+ *  License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ *  02111-1307, USA.
+ *
+ * $Id: mbootpack.h,v 1.2 2005/03/23 10:38:37 tjd21 Exp $
+ *
+ */
+
+#ifndef __MBOOTPACK__H__
+#define __MBOOTPACK__H__
+
+#ifndef __MB_ASM
+
+#undef NDEBUG
+#include <stdio.h>
+
+/* Flags */
+extern int quiet;
+
+/* Types */
+typedef unsigned long address_t;
+
+typedef struct section_t {
+    char *buffer;
+    address_t start;
+    long int size;
+    struct section_t *prev;
+    struct section_t *next;
+} section_t;
+
+/* buildimage.c */
+extern void make_bzImage(section_t *sections, 
+                         address_t entry, 
+                         address_t mbi, 
+                         FILE *fp);
+
+address_t place_mbi(long int size);
+
+
+/* trampoline.S */
+extern unsigned char mb_trampoline[];
+extern unsigned char mb_trampoline_end[];
+extern volatile address_t mb_mbi_address, mb_entry_address;
+
+/* Macros */
+#define MIN(_x,_y) (((_x)<=(_y))?(_x):(_y))
+#define MAX(_x,_y) (((_x)<=(_y))?(_y):(_x))
+#define ROUNDUP_P2(_x, _a) (((_x)+((_a)-1))&(~((_a)-1)))
+
+#endif
+
+/* x86 memory: such fun */
+#define MEM_HOLE_START  0xa0000
+#define MEM_HOLE_END    0x100000
+#define HIGHMEM_START   MEM_HOLE_END
+#define X86_PAGE_SIZE   0x1000
+
+/* How much command line we'll take from the bootloader. */
+#define CMD_LINE_SPACE  0x300
+
+/* Number of 512-byte sectors to load in low memory (max 7) */
+#define SETUPSECTS     7
+
+
+/* Who are we? */
+#define MBOOTPACK_VERSION_STRING "v0.2 (alpha)"
+
+#endif /* __MBOOTPACK__H__ */
+
+/*
+ *  EOF (mbootpack.h)
+ */
+
diff --git a/tools/misc/mbootpack/setup.S b/tools/misc/mbootpack/setup.S
new file mode 100644 (file)
index 0000000..f429312
--- /dev/null
@@ -0,0 +1,1064 @@
+/*
+ *  bootsect.S
+ *
+ *  This is setup.S from the linux 2.6.9 source code,
+ *  with heavy cuts and changes for mbootpack
+ *  November 2004 Tim Deegan <tjd21@cl.cam.ac.uk>
+ *
+ *  
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License as
+ *  published by the Free Software Foundation; either version 2 of the
+ *  License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ *  02111-1307, USA.
+ *
+ * $Id: setup.S,v 1.4 2005/03/23 10:39:03 tjd21 Exp $
+ *
+ */
+       
+#include "mbootpack.h"
+               
+/*
+ *     setup.S         Copyright (C) 1991, 1992 Linus Torvalds
+ *
+ * setup.s is responsible for getting the system data from the BIOS,
+ * and putting them into the appropriate places in system memory.
+ * both setup.s and system has been loaded by the bootblock.
+ *
+ * This code asks the bios for memory/disk/other parameters, and
+ * puts them in a "safe" place: 0x90000-0x901FF, ie where the
+ * boot-block used to be. It is then up to the protected mode
+ * system to read them from there before the area is overwritten
+ * for buffer-blocks.
+ *
+ * Move PS/2 aux init code to psaux.c
+ * (troyer@saifr00.cfsat.Honeywell.COM) 03Oct92
+ *
+ * some changes and additional features by Christoph Niemann,
+ * March 1993/June 1994 (Christoph.Niemann@linux.org)
+ *
+ * add APM BIOS checking by Stephen Rothwell, May 1994
+ * (sfr@canb.auug.org.au)
+ *
+ * High load stuff, initrd support and position independency
+ * by Hans Lermen & Werner Almesberger, February 1996
+ * <lermen@elserv.ffm.fgan.de>, <almesber@lrc.epfl.ch>
+ *
+ * Video handling moved to video.S by Martin Mares, March 1996
+ * <mj@k332.feld.cvut.cz>
+ *
+ * Extended memory detection scheme retwiddled by orc@pell.chi.il.us (david
+ * parsons) to avoid loadlin confusion, July 1997
+ *
+ * Transcribed from Intel (as86) -> AT&T (gas) by Chris Noe, May 1999.
+ * <stiker@northlink.com>
+ *
+ * Fix to work around buggy BIOSes which dont use carry bit correctly
+ * and/or report extended memory in CX/DX for e801h memory size detection 
+ * call.  As a result the kernel got wrong figures.  The int15/e801h docs
+ * from Ralf Brown interrupt list seem to indicate AX/BX should be used
+ * anyway.  So to avoid breaking many machines (presumably there was a reason
+ * to orginally use CX/DX instead of AX/BX), we do a kludge to see
+ * if CX/DX have been changed in the e801 call and if so use AX/BX .
+ * Michael Miller, April 2001 <michaelm@mjmm.org>
+ *
+ * New A20 code ported from SYSLINUX by H. Peter Anvin. AMD Elan bugfixes
+ * by Robert Schwebel, December 2001 <robert@schwebel.de>
+ */
+
+/*
+#include <linux/config.h>
+#include <asm/segment.h>
+#include <linux/version.h>
+#include <linux/compile.h>
+#include <asm/boot.h>
+#include <asm/e820.h>
+#include <asm/page.h>
+*/
+
+/* Definitions that should have come from these includes */
+#define DEF_INITSEG     0x9000
+#define DEF_SYSSEG      0x1000
+#define DEF_SETUPSEG    0x9020
+#define DEF_SYSSIZE     0x7F00
+#define NORMAL_VGA      0xffff
+#define EXTENDED_VGA    0xfffe
+#define ASK_VGA         0xfffd
+#define GDT_ENTRY_BOOT_CS      2
+#define __BOOT_CS              (GDT_ENTRY_BOOT_CS * 8)
+#define GDT_ENTRY_BOOT_DS      (GDT_ENTRY_BOOT_CS + 1)
+#define __BOOT_DS              (GDT_ENTRY_BOOT_DS * 8)
+#define __PAGE_OFFSET           (0xC0000000)
+#define E820MAP 0x2d0           /* our map */
+#define E820MAX 32              /* number of entries in E820MAP */
+#define E820NR  0x1e8           /* # entries in E820MAP */
+#define E820_RAM        1
+#define E820_RESERVED   2
+#define E820_ACPI       3 /* usable as RAM once ACPI tables have been read */
+#define E820_NVS        4
+#define __BIG_KERNEL__
+       
+               
+/* Signature words to ensure LILO loaded us right */
+#define SIG1   0xAA55
+#define SIG2   0x5A5A
+       
+INITSEG  = DEF_INITSEG         # 0x9000, we move boot here, out of the way
+SYSSEG   = DEF_SYSSEG          # 0x1000, system loaded at 0x10000 (65536).
+SETUPSEG = DEF_SETUPSEG                # 0x9020, this is the current segment
+                               # ... and the former contents of CS
+
+DELTA_INITSEG = SETUPSEG - INITSEG     # 0x0020
+
+.code16
+.globl _start, begtext, begdata, begbss, endtext, enddata, endbss
+
+.text
+begtext:
+.data
+begdata:
+.bss
+begbss:
+.text
+
+_start:
+start:
+       jmp     trampoline
+
+# This is the setup header, and it must start at %cs:2 (old 0x9020:2)
+
+               .ascii  "HdrS"          # header signature
+               .word   0x0203          # header version number (>= 0x0105)
+                                       # or else old loadlin-1.5 will fail)
+realmode_swtch:        .word   0, 0            # default_switch, SETUPSEG
+start_sys_seg: .word   SYSSEG
+               .word   kernel_version  # pointing to kernel version string
+                                       # above section of header is compatible
+                                       # with loadlin-1.5 (header v1.5). Don't
+                                       # change it.
+
+type_of_loader:        .byte   0               # = 0, old one (LILO, Loadlin,
+                                       #      Bootlin, SYSLX, bootsect...)
+                                       # See Documentation/i386/boot.txt for
+                                       # assigned ids
+       
+# flags, unused bits must be zero (RFU) bit within loadflags
+loadflags:
+LOADED_HIGH    = 1                     # If set, the kernel is loaded high
+CAN_USE_HEAP   = 0x80                  # If set, the loader also has set
+                                       # heap_end_ptr to tell how much
+                                       # space behind setup.S can be used for
+                                       # heap purposes.
+                                       # Only the loader knows what is free
+#ifndef __BIG_KERNEL__
+               .byte   0
+#else
+               .byte   LOADED_HIGH
+#endif
+
+setup_move_size: .word  0x8000         # size to move, when setup is not
+                                       # loaded at 0x90000. We will move setup 
+                                       # to 0x90000 then just before jumping
+                                       # into the kernel. However, only the
+                                       # loader knows how much data behind
+                                       # us also needs to be loaded.
+
+/* N.B. these next addresses are entirely ignored by this code -- it
+ * assumes it was loaded with the 32bit code at 0x100000, and doesn't 
+ * touch the ramdisk. */
+code32_start:                          # here loaders can put a different
+                                       # start address for 32-bit code.
+#ifndef __BIG_KERNEL__
+               .long   0x1000          #   0x1000 = default for zImage
+#else
+               .long   0x100000        # 0x100000 = default for big kernel
+#endif
+
+ramdisk_image: .long   0               # address of loaded ramdisk image
+                                       # Here the loader puts the 32-bit
+                                       # address where it loaded the image.
+                                       # This only will be read by the kernel.
+
+ramdisk_size:  .long   0               # its size in bytes
+
+bootsect_kludge:
+               .long   0               # obsolete
+
+heap_end_ptr:  .word   modelist+1024   # (Header version 0x0201 or later)
+                                       # space from here (exclusive) down to
+                                       # end of setup code can be used by setup
+                                       # for local heap purposes.
+
+pad1:          .word   0
+cmd_line_ptr:  .long 0                 # (Header version 0x0202 or later)
+                                       # If nonzero, a 32-bit pointer
+                                       # to the kernel command line.
+                                       # The command line should be
+                                       # located between the start of
+                                       # setup and the end of low
+                                       # memory (0xa0000), or it may
+                                       # get overwritten before it
+                                       # gets read.  If this field is
+                                       # used, there is no longer
+                                       # anything magical about the
+                                       # 0x90000 segment; the setup
+                                       # can be located anywhere in
+                                       # low memory 0x10000 or higher.
+
+ramdisk_max:   .long (-__PAGE_OFFSET-(512 << 20)-1) & 0x7fffffff
+                                       # (Header version 0x0203 or later)
+                                       # The highest safe address for
+                                       # the contents of an initrd
+
+/* Add more known locations: the image builder will overwrite
+ * these with the entry point and MBI location for the multiboot kernel.
+ * These offsets *must* match the definitions in buildimage.c  */
+
+entry_address: .long 0         # This will be offset 0x30 (0x230 from b'sect)
+mbi_address:   .long 0         # This will be offset 0x34
+
+/* Storage space for the size of memory */
+highmem_size:  .long 0
+               
+trampoline:    call    start_of_setup
+               .space  1024
+# End of setup header #####################################################
+
+start_of_setup:
+# Bootlin depends on this being done early
+       movw    $0x01500, %ax
+       movb    $0x81, %dl
+       int     $0x13
+
+#ifdef SAFE_RESET_DISK_CONTROLLER
+# Reset the disk controller.
+       movw    $0x0000, %ax
+       movb    $0x80, %dl
+       int     $0x13
+#endif
+
+# Set %ds = %cs, we know that SETUPSEG = %cs at this point
+       movw    %cs, %ax                # aka SETUPSEG
+       movw    %ax, %ds
+       
+# Check signature at end of setup      
+       cmpw    $SIG1, setup_sig1
+       jne     bad_sig
+
+       cmpw    $SIG2, setup_sig2
+       jne     bad_sig
+
+       jmp     good_sig1
+
+# Routine to print asciiz string at ds:si
+prtstr:
+       lodsb
+       andb    %al, %al
+       jz      fin
+
+       call    prtchr
+       jmp     prtstr
+
+fin:   ret
+
+# Space printing
+prtsp2:        call    prtspc          # Print double space
+prtspc:        movb    $0x20, %al      # Print single space (note: fall-thru)
+
+# Part of above routine, this one just prints ascii al
+prtchr:        pushw   %ax
+       pushw   %cx
+       movw    $7,%bx
+       movw    $0x01, %cx
+       movb    $0x0e, %ah
+       int     $0x10
+       popw    %cx
+       popw    %ax
+       ret
+
+beep:  movb    $0x07, %al
+       jmp     prtchr
+       
+no_sig_mess: .string   "No setup signature found ..."
+
+good_sig1:
+       jmp     good_sig
+
+# We now have to find the rest of the setup code/data
+bad_sig:
+       movw    %cs, %ax                        # SETUPSEG
+       subw    $DELTA_INITSEG, %ax             # INITSEG
+       movw    %ax, %ds
+       xorb    %bh, %bh
+       movb    (497), %bl                      # get setup sect from bootsect
+       subw    $4, %bx                         # LILO loads 4 sectors of setup
+       shlw    $8, %bx                         # convert to words (1sect=2^8 words)
+       movw    %bx, %cx
+       shrw    $3, %bx                         # convert to segment
+       addw    $SYSSEG, %bx
+       movw    %bx, %cs:start_sys_seg
+# Move rest of setup code/data to here
+       movw    $2048, %di                      # four sectors loaded by LILO
+       subw    %si, %si
+       pushw   %cs
+       popw    %es
+       movw    $SYSSEG, %ax
+       movw    %ax, %ds
+       rep
+       movsw
+       movw    %cs, %ax                        # aka SETUPSEG
+       movw    %ax, %ds
+       cmpw    $SIG1, setup_sig1
+       jne     no_sig
+
+       cmpw    $SIG2, setup_sig2
+       jne     no_sig
+
+       jmp     good_sig
+
+no_sig:
+       lea     no_sig_mess, %si
+       call    prtstr
+
+no_sig_loop:
+       hlt
+       jmp     no_sig_loop
+
+mb_hello_mess1:
+       .string "mboot"
+       
+good_sig:
+       lea     mb_hello_mess1, %si
+       call    prtstr
+
+       movw    %cs, %ax                        # aka SETUPSEG
+       subw    $DELTA_INITSEG, %ax             # aka INITSEG
+       movw    %ax, %ds
+# Check if an old loader tries to load a big-kernel
+       testb   $LOADED_HIGH, %cs:loadflags     # Do we have a big kernel?
+       jz      loader_ok                       # No, no danger for old loaders.
+
+       cmpb    $0, %cs:type_of_loader          # Do we have a loader that
+                                               # can deal with us?
+       jnz     loader_ok                       # Yes, continue.
+
+       pushw   %cs                             # No, we have an old loader,
+       popw    %ds                             # die. 
+       lea     loader_panic_mess, %si
+       call    prtstr
+
+       jmp     no_sig_loop
+
+loader_panic_mess: .string "Wrong loader, giving up..."
+
+loader_ok:
+       
+# Get memory size (extended mem, kB)
+
+/* We'll be storing this in highmem_size, to be copied to the mbi */
+
+# Try three different memory detection schemes.  First, try
+# e820h, which lets us assemble a memory map, then try e801h,
+# which returns a 32-bit memory size, and finally 88h, which
+# returns 0-64m
+
+       xorl    %edx, %edx
+       xorl    %eax, %eax
+       movl    %eax, (0x1e0)
+       movl    %eax, highmem_size
+       movb    %al, (E820NR)
+       
+# method E820H:
+# the memory map from hell.  e820h returns memory classified into
+# a whole bunch of different types, and allows memory holes and
+# everything.  We scan through this memory map and build a list
+# of the first 32 memory areas, which we return at [E820MAP].
+# This is documented at http://www.acpi.info/, in the ACPI 2.0 specification.
+
+#define SMAP  0x534d4150
+
+meme820:
+       xorl    %ebx, %ebx                      # continuation counter
+       movw    $E820MAP, %di                   # point into the whitelist
+                                               # so we can have the bios
+                                               # directly write into it.
+
+jmpe820:
+       movl    $0x0000e820, %eax               # e820, upper word zeroed
+       movl    $SMAP, %edx                     # ascii 'SMAP'
+       movl    $20, %ecx                       # size of the e820rec
+       pushw   %ds                             # data record.
+       popw    %es
+       int     $0x15                           # make the call
+       jc      bail820                         # fall to e801 if it fails
+
+       cmpl    $SMAP, %eax                     # check the return is `SMAP'
+       jne     bail820                         # fall to e801 if it fails
+
+#      cmpl    $1, 16(%di)                     # is this usable memory?
+#      jne     again820
+
+       # If this is usable memory, we save it by simply advancing %di by
+       # sizeof(e820rec).
+       #
+good820:
+       movb    (E820NR), %al                   # up to 32 entries
+       cmpb    $E820MAX, %al
+       jnl     bail820
+
+       incb    (E820NR)
+       movw    %di, %ax
+       addw    $20, %ax
+       movw    %ax, %di
+again820:
+       cmpl    $0, %ebx                        # check to see if
+       jne     jmpe820                         # %ebx is set to EOF    
+
+/* Multiboot spec says high mem should be the address of the first
+ * upper memory hole, minus 1 MB */
+       xorl    %ebx, %ebx
+       xorl    %ecx, %ecx
+       xorl    %edx, %edx
+       movw    $E820MAP, %di                   # Start at the beginning
+calc_highmem_loop:
+       cmpl    $1, 16(%di)                     # is it usable memory?
+       jnz     calc_highmem_next
+       cmpl    $0, 4(%di)                      # is base < 4GB?
+       jnz     calc_highmem_next
+       cmpl    $0x100000, 0(%di)               # is base <= 1MB?
+       jg      calc_highmem_next
+       movl    8(%di), %ecx                    # Calculate base+length
+       shrl    $10, %ecx                       # in kilobytes
+       movl    12(%di), %edx
+       shll    $22, %edx
+       orl     %edx, %ecx
+       movl    0(%di), %edx
+       shrl    $10, %edx
+       addl    %edx, %ecx
+       subl    $1024, %ecx                     # - 1 MB
+       cmpl    %cs:highmem_size, %ecx
+       jl      calc_highmem_next
+       movl    %ecx, %cs:highmem_size
+calc_highmem_next:
+       add     $1, %bl
+       add     $20, %di
+       cmp     %bl, (E820NR)
+       je      calc_highmem_done
+       jmp     calc_highmem_loop
+calc_highmem_done:
+                       
+bail820:
+
+# method E801H:
+# memory size is in 1k chunksizes, to avoid confusing loadlin.
+
+meme801:
+       stc                                     # fix to work around buggy
+       xorw    %cx,%cx                         # BIOSes which dont clear/set
+       xorw    %dx,%dx                         # carry on pass/error of
+                                               # e801h memory size call
+                                               # or merely pass cx,dx though
+                                               # without changing them.
+       movw    $0xe801, %ax
+       int     $0x15
+       jc      mem88
+
+       cmpw    $0x0, %cx                       # Kludge to handle BIOSes
+       jne     e801usecxdx                     # which report their extended
+       cmpw    $0x0, %dx                       # memory in AX/BX rather than
+       jne     e801usecxdx                     # CX/DX.  The spec I have read
+       movw    %ax, %cx                        # seems to indicate AX/BX 
+       movw    %bx, %dx                        # are more reasonable anyway...
+
+e801usecxdx:
+       andl    $0xffff, %edx                   # clear sign extend
+       shll    $6, %edx                        # and go from 64k to 1k chunks
+       andl    $0xffff, %ecx                   # clear sign extend
+       addl    %ecx, %edx
+
+       cmpl    %cs:highmem_size, %edx          # store extended mem size
+       jl      mem88                           # if it's bigger than
+       movl    %edx, %cs:highmem_size          # what we already have
+       
+# Ye Olde Traditional Methode.  Returns the memory size (up to 16mb or
+# 64mb, depending on the bios) in ax.
+mem88:
+       movb    $0x88, %ah
+       int     $0x15
+
+       andl    $0xffff, %eax                   # clear sign extend
+       cmpl    %cs:highmem_size, %eax          # store extended mem size
+       jl      have_memsize                    # if it's bigger than
+       movl    %eax, %cs:highmem_size          # what we already have
+
+have_memsize:
+       
+/* Culled: HDD probes, APM, speedstep */
+
+# Now we want to move to protected mode ...
+       cmpw    $0, %cs:realmode_swtch
+       jz      rmodeswtch_normal
+
+       lcall   *%cs:realmode_swtch
+
+       jmp     rmodeswtch_end
+
+rmodeswtch_normal:
+        pushw  %cs
+       call    default_switch
+
+rmodeswtch_end:
+
+/* Culled: code to take the 32bit entry address from the loader */
+/* Culled: code to relocate non-bzImage kernels */
+       
+       # then we load the segment descriptors
+       movw    %cs, %ax                        # aka SETUPSEG
+       movw    %ax, %ds
+               
+# Check whether we need to be downward compatible with version <=201
+       cmpl    $0, cmd_line_ptr
+       jne     end_move_self           # loader uses version >=202 features
+       cmpb    $0x20, type_of_loader
+       je      end_move_self           # bootsect loader, we know of it
+
+# Boot loader doesnt support boot protocol version 2.02.
+# If we have our code not at 0x90000, we need to move it there now.
+# We also then need to move the params behind it (commandline)
+# Because we would overwrite the code on the current IP, we move
+# it in two steps, jumping high after the first one.
+       movw    %cs, %ax
+       cmpw    $SETUPSEG, %ax
+       je      end_move_self
+
+       cli                                     # make sure we really have
+                                               # interrupts disabled !
+                                               # because after this the stack
+                                               # should not be used
+       subw    $DELTA_INITSEG, %ax             # aka INITSEG
+       movw    %ss, %dx
+       cmpw    %ax, %dx
+       jb      move_self_1
+
+       addw    $INITSEG, %dx
+       subw    %ax, %dx                        # this will go into %ss after
+                                               # the move
+move_self_1:
+       movw    %ax, %ds
+       movw    $INITSEG, %ax                   # real INITSEG
+       movw    %ax, %es
+       movw    %cs:setup_move_size, %cx
+       std                                     # we have to move up, so we use
+                                               # direction down because the
+                                               # areas may overlap
+       movw    %cx, %di
+       decw    %di
+       movw    %di, %si
+       subw    $move_self_here+0x200, %cx
+       rep
+       movsb
+       ljmp    $SETUPSEG, $move_self_here
+
+move_self_here:
+       movw    $move_self_here+0x200, %cx
+       rep
+       movsb
+       movw    $SETUPSEG, %ax
+       movw    %ax, %ds
+       movw    %dx, %ss
+end_move_self:                                 # now we are at the right place
+
+#
+# Enable A20.  This is at the very best an annoying procedure.
+# A20 code ported from SYSLINUX 1.52-1.63 by H. Peter Anvin.
+# AMD Elan bug fix by Robert Schwebel.
+#
+
+#if defined(CONFIG_X86_ELAN)
+       movb $0x02, %al                 # alternate A20 gate
+       outb %al, $0x92                 # this works on SC410/SC520
+a20_elan_wait:
+       call a20_test
+       jz a20_elan_wait
+       jmp a20_done
+#endif
+
+
+A20_TEST_LOOPS         =  32           # Iterations per wait
+A20_ENABLE_LOOPS       = 255           # Total loops to try            
+
+
+#ifndef CONFIG_X86_VOYAGER
+a20_try_loop:
+
+       # First, see if we are on a system with no A20 gate.
+a20_none:
+       call    a20_test
+       jnz     a20_done
+
+       # Next, try the BIOS (INT 0x15, AX=0x2401)
+a20_bios:
+       movw    $0x2401, %ax
+       pushfl                                  # Be paranoid about flags
+       int     $0x15
+       popfl
+
+       call    a20_test
+       jnz     a20_done
+
+       # Try enabling A20 through the keyboard controller
+#endif /* CONFIG_X86_VOYAGER */
+a20_kbc:
+       call    empty_8042
+
+#ifndef CONFIG_X86_VOYAGER
+       call    a20_test                        # Just in case the BIOS worked
+       jnz     a20_done                        # but had a delayed reaction.
+#endif
+
+       movb    $0xD1, %al                      # command write
+       outb    %al, $0x64
+       call    empty_8042
+
+       movb    $0xDF, %al                      # A20 on
+       outb    %al, $0x60
+       call    empty_8042
+
+#ifndef CONFIG_X86_VOYAGER
+       # Wait until a20 really *is* enabled; it can take a fair amount of
+       # time on certain systems; Toshiba Tecras are known to have this
+       # problem.
+a20_kbc_wait:
+       xorw    %cx, %cx
+a20_kbc_wait_loop:
+       call    a20_test
+       jnz     a20_done
+       loop    a20_kbc_wait_loop
+
+       # Final attempt: use "configuration port A"
+a20_fast:
+       inb     $0x92, %al                      # Configuration Port A
+       orb     $0x02, %al                      # "fast A20" version
+       andb    $0xFE, %al                      # don't accidentally reset
+       outb    %al, $0x92
+
+       # Wait for configuration port A to take effect
+a20_fast_wait:
+       xorw    %cx, %cx
+a20_fast_wait_loop:
+       call    a20_test
+       jnz     a20_done
+       loop    a20_fast_wait_loop
+
+       # A20 is still not responding.  Try frobbing it again.
+       # 
+       decb    (a20_tries)
+       jnz     a20_try_loop
+       
+       movw    $a20_err_msg, %si
+       call    prtstr
+
+a20_die:
+       hlt
+       jmp     a20_die
+
+a20_tries:
+       .byte   A20_ENABLE_LOOPS
+
+a20_err_msg:
+       .ascii  "linux: fatal error: A20 gate not responding!"
+       .byte   13, 10, 0
+
+       # If we get here, all is good
+a20_done:
+
+
+#endif /* CONFIG_X86_VOYAGER */
+
+/* Another print, to show protected mode and A20 are OK */
+
+       jmp     mb_hello_mess2_end
+mb_hello_mess2:
+       .string "pack " 
+mb_hello_mess2_end:    
+       lea     mb_hello_mess2, %si
+       call    prtstr
+       
+# set up gdt and idt
+/*     lidt    idt_48                          # load idt with 0,0 */
+/* Multiboot kernels must set up their own IDT:        leave this for now, 
+ * so we can print diagnostics */
+       
+       xorl    %eax, %eax                      # Compute gdt_base
+       movw    %ds, %ax                        # (Convert %ds:gdt to a linear ptr)
+       shll    $4, %eax
+       addl    $gdt, %eax
+       movl    %eax, (gdt_48+2)
+       lgdt    gdt_48                          # load gdt with whatever is
+                                               # appropriate
+       
+# make sure any possible coprocessor is properly reset..
+       xorw    %ax, %ax
+       outb    %al, $0xf0
+       call    delay
+
+       outb    %al, $0xf1
+       call    delay
+
+       
+# well, that went ok, I hope. Now we mask all interrupts - the rest
+# is done in init_IRQ().
+       movb    $0xFF, %al                      # mask all interrupts for now
+       outb    %al, $0xA1
+       call    delay
+       
+       movb    $0xFB, %al                      # mask all irq's but irq2 which
+       outb    %al, $0x21                      # is cascaded
+
+# Well, that certainly wasn't fun :-(. Hopefully it works, and we don't
+# need no steenking BIOS anyway (except for the initial loading :-).
+# The BIOS-routine wants lots of unnecessary data, and it's less
+# "interesting" anyway. This is how REAL programmers do it.
+
+/* Tailor the jump below so the target is the 32bit trampoline code */
+
+       xorl    %eax, %eax                      # Calculate
+       movw    %cs, %ax                        # the linear
+        shll    $4, %eax                       # address of
+        addl    $trampoline32, %eax            # %cs:trampoline32
+       movl    %eax, %cs:code32                # Stick it into the jmpi
+
+       /* Load a 32-bit pointer to the entry address into %ecx */
+       xorl    %ecx, %ecx                      # Calculate
+       movw    %cs, %cx                        # the linear
+        shll    $4, %ecx                       # address of
+        addl    $entry_address, %ecx           # %cs:entry_address
+
+# Well, now's the time to actually move into protected mode.
+
+       lea     mb_ready_mess, %si
+       call    prtstr
+       
+/* May as well load this IDT now */
+       lidt    idt_48
+
+       xorl    %eax, %eax
+       movw    $1, %ax                         # protected mode (PE) bit
+       lmsw    %ax                             # This is it!
+       jmp     flush_instr
+flush_instr:   
+       
+       /* Set up segment registers */
+       movw    $__BOOT_DS, %dx
+       movw    %dx, %ds
+       movw    %dx, %es
+       movw    %dx, %fs
+       movw    %dx, %gs
+       movw    %dx, %ss
+
+       /* Trampoline expects this in %eax */
+       movl    %ecx, %eax
+       
+       /* Jump to the 32-bit trampoline */
+
+# NOTE: For high loaded big kernels we need a
+#      jmpi    0x100000,__BOOT_CS
+#
+#      but we yet haven't reloaded the CS register, so the default size 
+#      of the target offset still is 16 bit.
+#       However, using an operand prefix (0x66), the CPU will properly
+#      take our 48 bit far pointer. (INTeL 80386 Programmer's Reference
+#      Manual, Mixing 16-bit and 32-bit code, page 16-6)
+
+       .byte 0x66, 0xea                        # prefix + jmpi-opcode
+code32:        .long   0x1000                          # will be set to trampoline32
+                                               # by code above.
+       .word   __BOOT_CS
+
+# Here's a bunch of information about your current kernel..
+
+kernel_version:         .string "mbootpack changeling bzImage"
+mb_ready_mess: 
+               .ascii MBOOTPACK_VERSION_STRING
+               .ascii "\r\n"
+               .byte 0
+
+# This is the default real mode switch routine.
+# to be called just before protected mode transition
+default_switch:
+       cli                                     # no interrupts allowed !
+       movb    $0x80, %al                      # disable NMI for bootup
+                                               # sequence
+       outb    %al, $0x70
+       lret
+
+
+#ifndef CONFIG_X86_VOYAGER
+# This routine tests whether or not A20 is enabled.  If so, it
+# exits with zf = 0.
+#
+# The memory address used, 0x200, is the int $0x80 vector, which
+# should be safe.
+
+A20_TEST_ADDR = 4*0x80
+
+a20_test:
+       pushw   %cx
+       pushw   %ax
+       xorw    %cx, %cx
+       movw    %cx, %fs                        # Low memory
+       decw    %cx
+       movw    %cx, %gs                        # High memory area
+       movw    $A20_TEST_LOOPS, %cx
+       movw    %fs:(A20_TEST_ADDR), %ax
+       pushw   %ax
+a20_test_wait:
+       incw    %ax
+       movw    %ax, %fs:(A20_TEST_ADDR)
+       call    delay                           # Serialize and make delay constant
+       cmpw    %gs:(A20_TEST_ADDR+0x10), %ax
+       loope   a20_test_wait
+
+       popw    %fs:(A20_TEST_ADDR)
+       popw    %ax
+       popw    %cx
+       ret     
+
+#endif /* CONFIG_X86_VOYAGER */
+
+# This routine checks that the keyboard command queue is empty
+# (after emptying the output buffers)
+#
+# Some machines have delusions that the keyboard buffer is always full
+# with no keyboard attached...
+#
+# If there is no keyboard controller, we will usually get 0xff
+# to all the reads.  With each IO taking a microsecond and
+# a timeout of 100,000 iterations, this can take about half a
+# second ("delay" == outb to port 0x80). That should be ok,
+# and should also be plenty of time for a real keyboard controller
+# to empty.
+#
+
+empty_8042:
+       pushl   %ecx
+       movl    $100000, %ecx
+
+empty_8042_loop:
+       decl    %ecx
+       jz      empty_8042_end_loop
+
+       call    delay
+
+       inb     $0x64, %al                      # 8042 status port
+       testb   $1, %al                         # output buffer?
+       jz      no_output
+
+       call    delay
+       inb     $0x60, %al                      # read it
+       jmp     empty_8042_loop
+
+no_output:
+       testb   $2, %al                         # is input buffer full?
+       jnz     empty_8042_loop                 # yes - loop
+empty_8042_end_loop:
+       popl    %ecx
+       ret
+
+# Read the cmos clock. Return the seconds in al
+gettime:
+       pushw   %cx
+       movb    $0x02, %ah
+       int     $0x1a
+       movb    %dh, %al                        # %dh contains the seconds
+       andb    $0x0f, %al
+       movb    %dh, %ah
+       movb    $0x04, %cl
+       shrb    %cl, %ah
+       aad
+       popw    %cx
+       ret
+
+# Delay is needed after doing I/O
+delay:
+       outb    %al,$0x80
+       ret
+
+# Descriptor tables
+#
+# NOTE: The intel manual says gdt should be sixteen bytes aligned for
+# efficiency reasons.  However, there are machines which are known not
+# to boot with misaligned GDTs, so alter this at your peril!  If you alter
+# GDT_ENTRY_BOOT_CS (in asm/segment.h) remember to leave at least two
+# empty GDT entries (one for NULL and one reserved).
+#
+# NOTE:        On some CPUs, the GDT must be 8 byte aligned.  This is
+# true for the Voyager Quad CPU card which will not boot without
+# This directive.  16 byte aligment is recommended by intel.
+#
+
+
+/* The boot-time code segment is set at the jmpi above */
+/* Dont change this without checking everything still matches  */
+
+       .align 16
+gdt:
+       .fill GDT_ENTRY_BOOT_CS,8,0
+
+       .word   0xFFFF                          # 4Gb - (0x100000*0x1000 = 4Gb)
+       .word   0                               # base address = 0
+       .word   0x9A00                          # code read/exec
+       .word   0x00CF                          # granularity = 4096, 386
+                                               #  (+5th nibble of limit)
+
+       .word   0xFFFF                          # 4Gb - (0x100000*0x1000 = 4Gb)
+       .word   0                               # base address = 0
+       .word   0x9200                          # data read/write
+       .word   0x00CF                          # granularity = 4096, 386
+                                               #  (+5th nibble of limit)
+gdt_end:
+       .align  4
+       
+       .word   0                               # alignment byte
+idt_48:
+       .word   0                               # idt limit = 0
+       .word   0, 0                            # idt base = 0L
+
+       .word   0                               # alignment byte
+gdt_48:
+       .word   gdt_end - gdt - 1               # gdt limit
+       .word   0, 0                            # gdt base (filled in later)
+
+# Include video setup & detection code
+
+/* #include "video.S" */
+
+.code32
+trampoline32:
+       /* Here, %eax = 32-bit pointer to entry_address */
+
+       /* Check if the bootloader gave us a (non-empty) command line */
+       movl    -8(%eax), %ebx                  # cmd_line_ptr
+       cmpl    $0, %ebx
+       je      no_cmd_line
+       cmpb    $0, 0(%ebx)
+       je      no_cmd_line
+
+       /* Find the MBI command line */
+       movl    %eax, %ecx                      # &entry_address
+       addl    $(begtext-entry_address), %ecx  # --> start of setup
+       subl    $0x9200, %ecx                   # --> reloc offset
+       movl    %ecx, %esi                      # (copy offset)
+       movl    %ecx, %ebx                      # (copy offset)
+       addl    4(%eax), %ecx                   # --> current addr of MBI
+       addl    16(%ecx), %ebx                  # --> cur. addr of MB cmdline
+
+       /* Overwrite the built-in MBI kernel command line */
+       movl    -8(%eax), %ecx
+       movl    $0, %edi
+
+       /* Give the kernel a 'self' word, that linux doesn't get */
+       movw    $0x202E, 0(%ebx)                        # '. '
+       addl    $0x2, %ebx
+       
+cmd_line_copy: 
+       movb    (%ecx, %edi), %dl
+       movb    %dl, (%ebx, %edi)
+       inc     %edi
+       cmp     $CMD_LINE_SPACE-3, %edi 
+       je      cmd_line_copy_end
+
+       cmpb    $0x0, %dl
+       jne     cmd_line_copy
+cmd_line_copy_end:
+       movb    $0x0, (%ebx, %edi)
+       subl    $0x2, %ebx
+       
+       /* Look for '--' in the kernel command line */
+cmd_line_scan:
+       inc     %ebx
+       cmpb    $0x0, 0(%ebx)
+       je      no_cmd_line
+       cmpl    $0x202D2D20, 0(%ebx)            # ' -- '
+       jne     cmd_line_scan
+
+       /* Found it: terminate kernel's command line */
+       movb    $0x0, 0(%ebx)
+       inc     %ebx
+       /* Relocate address to where it will be moved to */
+       subl    %esi, %ebx
+       
+       /* Is there a module 0? */
+       movl    %esi, %ecx                      # Reloc offset
+       addl    4(%eax), %ecx                   # --> current addr of MBI
+       cmpl    $0x0, 20(%ecx)                  # (check module count)
+       je      no_cmd_line
+       /* Overwrite module 0's command line */
+       movl    %esi, %edx                      # Reloc offset
+       addl    24(%ecx), %edx                  # --> cur. add. of Module 0
+       movl    %ebx, 8(%edx)                   # --> blat mod. 0's cmdline
+no_cmd_line:
+
+
+       /* Relocate the MBI from after the setup code to its proper home
+        * between the MBI pointer and 0xa000 */
+       movl    %eax, %ecx                      # &entry_address
+       addl    $(begtext-entry_address), %ecx  # --> start of setup
+       subl    $0x9200, %ecx                   # --> reloc offset
+       addl    4(%eax), %ecx                   # --> current addr of MBI
+       
+       movl    $0xa000, %ebx                   # End of MBI
+       subl    4(%eax), %ebx                   # --> size of MBI
+       movl    %ebx, %edi
+       
+       movl    4(%eax), %ebx                   # Destination of MBI
+       
+mbi_copy:
+       dec     %edi
+       movb    (%ecx, %edi), %dl
+       movb    %dl, (%ebx, %edi)
+       cmp     $0x0, %edi
+       jne     mbi_copy        
+       
+       /* Copy memory size into MBI structure */
+       movl    4(%eax), %ebx                   # MBI pointer
+       movl    8(%eax), %ecx                   # highmem_size
+       movl    %ecx, 8(%ebx)                   # --> mbi.mem_upper
+       movl    $0x280, %ecx
+       movl    %ecx, 4(%ebx)                   # --> mbi.mem_lower
+       /* Set the MB_INFO_MEMORY bit */
+       orl     $1, 0(%ebx)
+
+       /* Recover the MBI pointer into %ebx */
+       movl    4(%eax), %ebx                   # MBI pointer
+       /* Extract the load address into %ecx */
+       movl    0(%eax), %ecx
+       /* Let the kernel know we're a multiboot loader */
+       movl    $0x2BADB002, %eax
+       /* Jump to the kernel address supplied */
+       jmp     *%ecx
+
+# Setup signature -- must be last
+setup_sig1:    .word   SIG1
+setup_sig2:    .word   SIG2
+
+# After this point, there is some free space which is used by the video mode
+# handling code to store the temporary mode table (not used by the kernel).
+
+modelist:
+
+.text
+endtext:
+.data
+enddata:
+.bss
+endbss: